2
2
3
3
namespace PhpTwinfield \Mappers ;
4
4
5
+ use DOMElement ;
5
6
use DOMXPath ;
6
7
use Money \Currency ;
7
8
use Money \Money ;
18
19
use PhpTwinfield \Office ;
19
20
use PhpTwinfield \Response \Response ;
20
21
use PhpTwinfield \SalesTransaction ;
22
+ use PhpTwinfield \Transactions \MatchLine ;
23
+ use PhpTwinfield \Transactions \MatchSet ;
21
24
use PhpTwinfield \Transactions \TransactionFields \DueDateField ;
22
25
use PhpTwinfield \Transactions \TransactionFields \FreeTextFields ;
23
26
use PhpTwinfield \Transactions \TransactionFields \InvoiceNumberField ;
24
27
use PhpTwinfield \Transactions \TransactionFields \PaymentReferenceField ;
25
28
use PhpTwinfield \Transactions \TransactionFields \StatementNumberField ;
29
+ use PhpTwinfield \Transactions \TransactionLine ;
26
30
use PhpTwinfield \Transactions \TransactionLineFields \MatchDateField ;
27
31
use PhpTwinfield \Transactions \TransactionLineFields \PerformanceFields ;
28
32
use PhpTwinfield \Transactions \TransactionLineFields \ValueOpenField ;
29
33
use PhpTwinfield \Transactions \TransactionLineFields \VatTotalFields ;
30
34
use PhpTwinfield \Util ;
35
+ use UnexpectedValueException ;
31
36
32
37
class TransactionMapper
33
38
{
@@ -83,55 +88,60 @@ public static function map(string $transactionClassName, Response $response): Ba
83
88
$ transaction ->setRaiseWarning (Util::parseBoolean ($ raiseWarning ));
84
89
}
85
90
91
+ $ header = self ::getFirstChildElementByName ($ transactionElement , 'header ' );
92
+ if ($ header === null ) {
93
+ throw new UnexpectedValueException ('Transaction section is missing a header section ' );
94
+ }
95
+
86
96
$ office = new Office ();
87
- $ office ->setCode (self ::getField ($ transaction , $ transactionElement , 'office ' ));
97
+ $ office ->setCode (self ::getField ($ transaction , $ header , 'office ' ));
88
98
89
99
$ transaction
90
100
->setOffice ($ office )
91
- ->setCode (self ::getField ($ transaction , $ transactionElement , 'code ' ))
92
- ->setPeriod (self ::getField ($ transaction , $ transactionElement , 'period ' ))
93
- ->setDateFromString (self ::getField ($ transaction , $ transactionElement , 'date ' ))
94
- ->setOrigin (self ::getField ($ transaction , $ transactionElement , 'origin ' ))
95
- ->setFreetext1 (self ::getField ($ transaction , $ transactionElement , 'freetext1 ' ))
96
- ->setFreetext2 (self ::getField ($ transaction , $ transactionElement , 'freetext2 ' ))
97
- ->setFreetext3 (self ::getField ($ transaction , $ transactionElement , 'freetext3 ' ));
98
-
99
- $ currency = new Currency (self ::getField ($ transaction , $ transactionElement , 'currency ' ) ?? self ::DEFAULT_CURRENCY_CODE );
101
+ ->setCode (self ::getField ($ transaction , $ header , 'code ' ))
102
+ ->setPeriod (self ::getField ($ transaction , $ header , 'period ' ))
103
+ ->setDateFromString (self ::getField ($ transaction , $ header , 'date ' ))
104
+ ->setOrigin (self ::getField ($ transaction , $ header , 'origin ' ))
105
+ ->setFreetext1 (self ::getField ($ transaction , $ header , 'freetext1 ' ))
106
+ ->setFreetext2 (self ::getField ($ transaction , $ header , 'freetext2 ' ))
107
+ ->setFreetext3 (self ::getField ($ transaction , $ header , 'freetext3 ' ));
108
+
109
+ $ currency = new Currency (self ::getField ($ transaction , $ header , 'currency ' ) ?? self ::DEFAULT_CURRENCY_CODE );
100
110
$ transaction ->setCurrency ($ currency );
101
111
102
- $ number = self ::getField ($ transaction , $ transactionElement , 'number ' );
112
+ $ number = self ::getField ($ transaction , $ header , 'number ' );
103
113
if (!empty ($ number )) {
104
114
$ transaction ->setNumber ($ number );
105
115
}
106
116
107
117
if (Util::objectUses (DueDateField::class, $ transaction )) {
108
- $ value = self ::getField ($ transaction , $ transactionElement , 'duedate ' );
118
+ $ value = self ::getField ($ transaction , $ header , 'duedate ' );
109
119
110
120
if ($ value !== null ) {
111
121
$ transaction ->setDueDateFromString ($ value );
112
122
}
113
123
}
114
124
if (Util::objectUses (InvoiceNumberField::class, $ transaction )) {
115
- $ transaction ->setInvoiceNumber (self ::getField ($ transaction , $ transactionElement , 'invoicenumber ' ));
125
+ $ transaction ->setInvoiceNumber (self ::getField ($ transaction , $ header , 'invoicenumber ' ));
116
126
}
117
127
if (Util::objectUses (PaymentReferenceField::class, $ transaction )) {
118
128
$ transaction
119
- ->setPaymentReference (self ::getField ($ transaction , $ transactionElement , 'paymentreference ' ));
129
+ ->setPaymentReference (self ::getField ($ transaction , $ header , 'paymentreference ' ));
120
130
}
121
131
if (Util::objectUses (StatementNumberField::class, $ transaction )) {
122
- $ transaction ->setStatementnumber (self ::getField ($ transaction , $ transactionElement , 'statementnumber ' ));
132
+ $ transaction ->setStatementnumber (self ::getField ($ transaction , $ header , 'statementnumber ' ));
123
133
}
124
134
125
135
if ($ transaction instanceof SalesTransaction) {
126
- $ transaction ->setOriginReference (self ::getField ($ transaction , $ transactionElement , 'originreference ' ));
136
+ $ transaction ->setOriginReference (self ::getField ($ transaction , $ header , 'originreference ' ));
127
137
}
128
138
if ($ transaction instanceof JournalTransaction) {
129
- $ transaction ->setRegime (self ::getField ($ transaction , $ transactionElement , 'regime ' ));
139
+ $ transaction ->setRegime (self ::getField ($ transaction , $ header , 'regime ' ));
130
140
}
131
141
if ($ transaction instanceof CashTransaction) {
132
142
$ transaction ->setStartvalue (
133
143
Util::parseMoney (
134
- self ::getField ($ transaction , $ transactionElement , 'startvalue ' ),
144
+ self ::getField ($ transaction , $ header , 'startvalue ' ),
135
145
$ transaction ->getCurrency ()
136
146
)
137
147
);
@@ -140,6 +150,7 @@ public static function map(string $transactionClassName, Response $response): Ba
140
150
// Parse the transaction lines
141
151
$ transactionLineClassName = $ transaction ->getLineClassName ();
142
152
153
+ /** @var DOMElement $lineElement */
143
154
foreach ((new DOMXPath ($ document ))->query ('/transaction/lines/line ' ) as $ lineElement ) {
144
155
self ::checkForMessage ($ transaction , $ lineElement );
145
156
@@ -163,6 +174,11 @@ public static function map(string $transactionClassName, Response $response): Ba
163
174
->setMatchLevel (self ::getField ($ transaction , $ lineElement , 'matchlevel ' ))
164
175
->setVatCode (self ::getField ($ transaction , $ lineElement , 'vatcode ' ));
165
176
177
+ $ matches = $ lineElement ->getElementsByTagName ('matches ' )->item (0 );
178
+ if ($ matches !== null ) {
179
+ self ::parseMatches ($ transaction , $ transactionLine , $ matches );
180
+ }
181
+
166
182
// TODO - according to the docs, the field is called <basevalueopen>, but the examples use <openbasevalue>.
167
183
$ baseValueOpen = self ::getFieldAsMoney ($ transaction , $ lineElement , 'basevalueopen ' , $ currency ) ?: self ::getFieldAsMoney ($ transaction , $ lineElement , 'openbasevalue ' , $ currency );
168
184
if ($ baseValueOpen ) {
@@ -255,9 +271,22 @@ public static function map(string $transactionClassName, Response $response): Ba
255
271
return $ transaction ;
256
272
}
257
273
258
- private static function getField ( BaseTransaction $ transaction , \ DOMElement $ element , string $ fieldTagName ): ?string
274
+ private static function getFirstChildElementByName ( DOMElement $ element , string $ fieldTagName ): ?DOMElement
259
275
{
260
- $ fieldElement = $ element ->getElementsByTagName ($ fieldTagName )->item (0 );
276
+ $ fieldElement = null ;
277
+ foreach ($ element ->childNodes as $ node ) {
278
+ if ($ node ->nodeName === $ fieldTagName ) {
279
+ $ fieldElement = $ node ;
280
+ break ;
281
+ }
282
+ }
283
+
284
+ return $ fieldElement ;
285
+ }
286
+
287
+ private static function getField (BaseTransaction $ transaction , DOMElement $ element , string $ fieldTagName ): ?string
288
+ {
289
+ $ fieldElement = self ::getFirstChildElementByName ($ element , $ fieldTagName );
261
290
262
291
if (!isset ($ fieldElement )) {
263
292
return null ;
@@ -270,7 +299,7 @@ private static function getField(BaseTransaction $transaction, \DOMElement $elem
270
299
271
300
private static function getFieldAsMoney (
272
301
BaseTransaction $ transaction ,
273
- \ DOMElement $ element ,
302
+ DOMElement $ element ,
274
303
string $ fieldTagName ,
275
304
Currency $ currency
276
305
): ?Money {
@@ -283,7 +312,7 @@ private static function getFieldAsMoney(
283
312
return new Money ((string )(100 * $ fieldValue ), $ currency );
284
313
}
285
314
286
- private static function checkForMessage (BaseTransaction $ transaction , \ DOMElement $ element ): void
315
+ private static function checkForMessage (BaseTransaction $ transaction , DOMElement $ element ): void
287
316
{
288
317
if ($ element ->hasAttribute ('msg ' )) {
289
318
$ message = new Message ();
@@ -294,4 +323,31 @@ private static function checkForMessage(BaseTransaction $transaction, \DOMElemen
294
323
$ transaction ->addMessage ($ message );
295
324
}
296
325
}
326
+
327
+ private static function parseMatches (BaseTransaction $ baseTransaction , BaseTransactionLine $ transactionLine , DOMElement $ element ): void
328
+ {
329
+ /** @var DOMElement $set */
330
+ foreach ($ element ->getElementsByTagName ('set ' ) as $ set ) {
331
+ $ status = Destiny::from ($ set ->getAttribute ('status ' ));
332
+ $ matchDate = Util::parseDate (self ::getField ($ baseTransaction , $ set , 'matchdate ' ));
333
+ $ matchValue = self ::getFieldAsMoney ($ baseTransaction , $ set , 'matchvalue ' , $ baseTransaction ->getCurrency ());
334
+
335
+ $ matchLines = [];
336
+ /** @var DOMElement $lines */
337
+ $ lines = $ set ->getElementsByTagName ('lines ' )->item (0 );
338
+ /** @var DOMElement $line */
339
+ foreach ($ lines ->childNodes as $ line ) {
340
+ if ($ line ->nodeName !== 'line ' ) {
341
+ continue ;
342
+ }
343
+ $ code = (string )self ::getField ($ baseTransaction , $ line , 'code ' );
344
+ $ number = (int )self ::getField ($ baseTransaction , $ line , 'number ' );
345
+ $ lineNum = (int )self ::getField ($ baseTransaction , $ line , 'line ' );
346
+ $ lineMatchValue = self ::getFieldAsMoney ($ baseTransaction , $ line , 'matchvalue ' , $ baseTransaction ->getCurrency ());
347
+
348
+ $ matchLines [] = new MatchLine ($ code , $ number , $ lineNum , $ lineMatchValue );
349
+ }
350
+ $ transactionLine ->addMatch (new MatchSet ($ status , $ matchDate , $ matchValue , $ matchLines ));
351
+ }
352
+ }
297
353
}
0 commit comments