Passed
Push — main ( 45a540...bf08fb )
by Daniel
02:14
created

ElectronicInvoiceWrite::setSingleComment()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * The MIT License (MIT)
6
 *
7
 * Copyright (c) 2024 Daniel Popiniuc
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
 * SOFTWARE.
26
 *
27
 */
28
29
namespace danielgp\efactura;
30
31
class ElectronicInvoiceWrite
32
{
33
34
    use TraitVersions;
35
36
    protected \XMLWriter $objXmlWriter;
37
38
    private function setDocumentTag(array $arrayDocumentData): void
39
    {
40
        $this->objXmlWriter->startElement($arrayDocumentData['DocumentTagName']);
41
        foreach ($arrayDocumentData['DocumentNameSpaces'] as $key => $value) {
42
            if ($key === '') {
43
                $strValue = sprintf($value, $arrayDocumentData['DocumentTagName']);
44
                $this->objXmlWriter->writeAttributeNS(null, 'xmlns', null, $strValue);
45
            } else {
46
                $this->objXmlWriter->writeAttributeNS('xmlns', $key, null, $value);
47
            }
48
        }
49
        if (array_key_exists('SchemaLocation', $arrayDocumentData)) {
50
            $this->objXmlWriter->writeAttribute('xsi:schemaLocation', $arrayDocumentData['SchemaLocation']);
51
        }
52
    }
53
54
    private function setElementComment(string $strKey): void
55
    {
56
        if (array_key_exists($strKey, $this->arraySettings['Comments'])) {
57
            $elementComment = $this->arraySettings['Comments'][$strKey];
58
            if (is_array($elementComment)) {
59
                foreach ($elementComment as $value) {
60
                    $this->objXmlWriter->writeComment($value);
61
                }
62
            } else {
63
                $this->objXmlWriter->writeComment($elementComment);
64
            }
65
        }
66
    }
67
68
    private function setElementsOrdered(array $arrayInput): void
69
    {
70
        $this->setElementComment($arrayInput['commentParentKey']);
71
        $this->objXmlWriter->startElement('cac:' . $arrayInput['tag']);
72
        $this->setExtraElement($arrayInput, 'Start');
73
        $arrayCustomOrder = $this->arraySettings['CustomOrder'][$arrayInput['commentParentKey']];
74
        foreach ($arrayCustomOrder as $value) { // get the values in expected order
75
            if (array_key_exists($value, $arrayInput['data'])) { // because certain value are optional
76
                $key         = implode('_', [$arrayInput['commentParentKey'], $value]);
77
                $matches     = [];
78
                preg_match('/^.*(Amount|Quantity)$/', $value, $matches, PREG_OFFSET_CAPTURE);
79
                $strCategory = $this->setCategorizedVerifications([
80
                    'commentParentKey' => $arrayInput['commentParentKey'],
81
                    'data'             => $arrayInput['data'][$value],
82
                    'matches'          => $matches,
83
                    'tag'              => $value,
84
                ]);
85
                switch ($strCategory) {
86
                    case 'ArrayElementsOrdered':
87
                        foreach ($arrayInput['data'][$value] as $value2) {
88
                            $this->setElementsOrdered([
89
                                'commentParentKey' => $key,
90
                                'data'             => $value2,
91
                                'tag'              => $value,
92
                            ]);
93
                        }
94
                        break;
95
                    case 'ElementsOrdered':
96
                        $this->setElementsOrdered([
97
                            'commentParentKey' => $key,
98
                            'data'             => $arrayInput['data'][$value],
99
                            'tag'              => $value,
100
                        ]);
101
                        break;
102
                    case 'MultipleElementsOrdered':
103
                        $this->setMultipleElementsOrdered([
104
                            'commentParentKey' => $key,
105
                            'data'             => $arrayInput['data'][$value],
106
                            'tag'              => $value,
107
                        ]);
108
                        break;
109
                    case 'SingleElementWithAttribute':
110
                        $this->setSingleElementWithAttribute([
111
                            'commentParentKey' => $arrayInput['commentParentKey'],
112
                            'data'             => $arrayInput['data'][$value],
113
                            'tag'              => $value,
114
                        ]);
115
                        break;
116
                }
117
            }
118
        }
119
        $this->setExtraElement($arrayInput, 'End');
120
        $this->objXmlWriter->endElement(); // $key
121
    }
122
123
    private function setExtraElement(array $arrayInput, string $strType): void
124
    {
125
        if (in_array($arrayInput['tag'], ['AccountingCustomerParty', 'AccountingSupplierParty'])) {
126
            switch ($strType) {
127
                case 'End':
128
                    $this->objXmlWriter->endElement();
129
                    break;
130
                case 'Start':
131
                    $this->objXmlWriter->startElement('cac:Party');
132
                    break;
133
            }
134
        }
135
    }
136
137
    private function setHeaderCommonBasicComponents(array $arrayElementWithData): void
138
    {
139
        $arrayCustomOrdered = $this->arraySettings['CustomOrder']['Header_CBC'];
140
        foreach ($arrayCustomOrdered as $value) {
141
            if (array_key_exists($value, $arrayElementWithData)) {
142
                $this->setElementComment($value);
143
                $this->objXmlWriter->writeElement('cbc:' . $value, $arrayElementWithData[$value]);
144
            }
145
        }
146
    }
147
148
    private function setMultipleElementsOrdered(array $arrayData): void
149
    {
150
        foreach ($arrayData['data'] as $value) {
151
            $strCommentParentKey = $this->setManageComment($arrayData['commentParentKey'], $value);
152
            $this->setElementsOrdered([
153
                'commentParentKey' => $strCommentParentKey,
154
                'data'             => $value,
155
                'tag'              => $arrayData['tag'],
156
            ]);
157
        }
158
    }
159
160
    private function setPrepareXml(string $strFile, int $intIdent = 4): void
161
    {
162
        $this->objXmlWriter = new \XMLWriter();
163
        $this->objXmlWriter->openURI($strFile);
164
        $this->objXmlWriter->setIndent(true);
165
        $this->objXmlWriter->setIndentString(str_repeat(' ', $intIdent));
166
        $this->objXmlWriter->startDocument('1.0', 'UTF-8');
167
    }
168
169
    private function setProduceMiddleXml(array $arrayData): void
170
    {
171
        $arrayAggregates             = $arrayData['Header']['CommonAggregateComponents-2'];
172
        $arrayOptionalElementsHeader = $this->arrayProcessingDetails['OptionalElementsHeader'];
173
        foreach ($arrayOptionalElementsHeader as $key => $strLogicType) {
174
            if (array_key_exists($key, $arrayAggregates)) {
175
                switch ($strLogicType) {
176
                    case 'Multiple':
177
                        $this->setMultipleElementsOrdered([
178
                            'commentParentKey' => $key,
179
                            'data'             => $arrayAggregates[$key],
180
                            'tag'              => $key,
181
                        ]);
182
                        break;
183
                    case 'Single':
184
                        $this->setElementsOrdered([
185
                            'commentParentKey' => $key,
186
                            'data'             => $arrayAggregates[$key],
187
                            'tag'              => $key,
188
                        ]);
189
                        break;
190
                    case 'SingleCompany':
191
                        $this->setElementsOrdered([
192
                            'commentParentKey' => $key,
193
                            'data'             => $arrayAggregates[$key]['Party'],
194
                            'tag'              => $key,
195
                        ]);
196
                        break;
197
                }
198
            }
199
        }
200
    }
201
202
    private function setSingleComment(array $arrayInput): void
203
    {
204
        if (array_key_exists('commentParentKey', $arrayInput)) {
205
            $this->setElementComment(implode('_', [$arrayInput['commentParentKey'], $arrayInput['tag']]));
206
            if (str_ends_with($arrayInput['tag'], 'Quantity')) {
207
                $this->setElementComment(implode('_', [$arrayInput['commentParentKey'], $arrayInput['tag']
208
                    . 'UnitOfMeasure']));
209
            }
210
        }
211
    }
212
213
    private function setSingleElementWithAttribute(array $arrayInput): void
214
    {
215
        $this->setSingleComment($arrayInput);
216
        if (is_array($arrayInput['data']) && array_key_exists('value', $arrayInput['data'])) {
217
            $this->objXmlWriter->startElement('cbc:' . $arrayInput['tag']);
218
            foreach ($arrayInput['data'] as $key => $value) {
219
                if ($key !== 'value') { // if is not value, must be an attribute
220
                    $this->objXmlWriter->writeAttribute($key, $value);
221
                }
222
            }
223
            $this->objXmlWriter->writeRaw($this->setNumericValue($arrayInput['tag'], $arrayInput['data']));
224
            $this->objXmlWriter->endElement();
225
        } else {
226
            $this->objXmlWriter->writeElement('cbc:' . $arrayInput['tag'], $arrayInput['data']);
227
        }
228
    }
229
230
    public function writeElectronicInvoice(string $strFile, array $inData, array $arrayFeatures): void
231
    {
232
        $this->getProcessingDetails();
233
        $arrayData = $this->loadSettingsAndManageDefaults($inData, $arrayFeatures);
234
        if (!array_key_exists('Ident', $arrayFeatures)) {
235
            $arrayFeatures['Ident'] = 4;
236
        }
237
        $this->setPrepareXml($strFile, $arrayFeatures['Ident']);
238
        $this->setDocumentTag($arrayData);
239
        $this->setHeaderCommonBasicComponents($arrayData['Header']['CommonBasicComponents-2']);
240
        $this->setProduceMiddleXml($arrayData);
241
        // multiple Lines
242
        $this->setMultipleElementsOrdered([
243
            'commentParentKey' => 'Lines',
244
            'data'             => $arrayData['Lines'],
245
            'tag'              => $arrayData['DocumentTagName'] . 'Line',
246
        ]);
247
        $this->objXmlWriter->endElement(); // Invoice or CreditNote
248
        $this->objXmlWriter->flush();
249
    }
250
}
251