Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.61% covered (danger)
0.61%
1 / 164
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Installer
0.61% covered (danger)
0.61%
1 / 164
0.00% covered (danger)
0.00%
0 / 5
1102.20
0.00% covered (danger)
0.00%
0 / 1
 install
4.00% covered (danger)
4.00%
1 / 25
0.00% covered (danger)
0.00%
0 / 1
50.35
 createBillAttributeTypes
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
42
 createBillAttributeValues
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
90
 createTaxCombination
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
30
 createBillTypes
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   Modules\Billing\Admin
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace Modules\Billing\Admin;
16
17use Modules\Billing\Models\BillTransferType;
18use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper;
19use Modules\ItemManagement\Models\Attribute\ItemAttributeTypeMapper;
20use Modules\SupplierManagement\Models\SupplierAttributeTypeMapper;
21use phpOMS\Application\ApplicationAbstract;
22use phpOMS\Config\SettingsInterface;
23use phpOMS\Message\Http\HttpRequest;
24use phpOMS\Message\Http\HttpResponse;
25use phpOMS\Module\InstallerAbstract;
26use phpOMS\Module\ModuleInfo;
27use phpOMS\Uri\HttpUri;
28
29/**
30 * Installer class.
31 *
32 * @package Modules\Billing\Admin
33 * @license OMS License 2.0
34 * @link    https://jingga.app
35 * @since   1.0.0
36 */
37final class Installer extends InstallerAbstract
38{
39    /**
40     * Path of the file
41     *
42     * @var string
43     * @since 1.0.0
44     */
45    public const PATH = __DIR__;
46
47    /**
48     * {@inheritdoc}
49     */
50    public static function install(ApplicationAbstract $app, ModuleInfo $info, SettingsInterface $cfgHandler) : void
51    {
52        parent::install($app, $info, $cfgHandler);
53
54        // Install bill type templates
55        $media = \Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Install/Media2.install.json']);
56
57        /** @var int $defaultTemplate */
58        $defaultTemplate = (int) \reset($media['upload'][0]);
59
60        /* Bill types */
61        $fileContent = \file_get_contents(__DIR__ . '/Install/types.json');
62        if ($fileContent === false) {
63            return;
64        }
65
66        /** @var array $types */
67        $types = \json_decode($fileContent, true);
68        if ($types === false) {
69            return;
70        }
71
72        self::createBillTypes($app, $types, $defaultTemplate);
73
74        /* Tax types */
75        $fileContent = \file_get_contents(__DIR__ . '/Install/Taxes/taxes.json');
76        if ($fileContent === false) {
77            return;
78        }
79
80        /** @var array $taxes */
81        $taxes = \json_decode($fileContent, true);
82        if ($taxes === false) {
83            return;
84        }
85
86        self::createTaxCombination($app, $taxes);
87
88        /* Attributes */
89        $fileContent = \file_get_contents(__DIR__ . '/Install/attributes.json');
90        if ($fileContent === false) {
91            return;
92        }
93
94        /** @var array $attributes */
95        $attributes = \json_decode($fileContent, true);
96        if ($attributes === false) {
97            return;
98        }
99
100        $attrTypes  = self::createBillAttributeTypes($app, $attributes);
101        $attrValues = self::createBillAttributeValues($app, $attrTypes, $attributes);
102    }
103
104    /**
105     * Install default attribute types
106     *
107     * @param ApplicationAbstract $app        Application
108     * @param array               $attributes Attribute definition
109     *
110     * @return array
111     *
112     * @since 1.0.0
113     */
114    private static function createBillAttributeTypes(ApplicationAbstract $app, array $attributes) : array
115    {
116        /** @var array $billAttrType */
117        $billAttrType = [];
118
119        /** @var \Modules\Billing\Controller\ApiController $module */
120        $module = $app->moduleManager->getModuleInstance('Billing');
121
122        /** @var array $attribute */
123        foreach ($attributes as $attribute) {
124            $response = new HttpResponse();
125            $request  = new HttpRequest(new HttpUri(''));
126
127            $request->header->account = 1;
128            $request->setData('name', $attribute['name'] ?? '');
129            $request->setData('title', \reset($attribute['l11n']));
130            $request->setData('language', \array_keys($attribute['l11n'])[0] ?? 'en');
131            $request->setData('is_required', $attribute['is_required'] ?? false);
132            $request->setData('custom', $attribute['is_custom_allowed'] ?? false);
133            $request->setData('validation_pattern', $attribute['validation_pattern'] ?? '');
134            $request->setData('datatype', (int) $attribute['value_type']);
135
136            $module->apiBillAttributeTypeCreate($request, $response);
137
138            $responseData = $response->get('');
139
140            if (!\is_array($responseData)) {
141                continue;
142            }
143
144            $billAttrType[$attribute['name']] = \is_array($responseData['response'])
145                ? $responseData['response']
146                : $responseData['response']->toArray();
147
148            $isFirst = true;
149            foreach ($attribute['l11n'] as $language => $l11n) {
150                if ($isFirst) {
151                    $isFirst = false;
152                    continue;
153                }
154
155                $response = new HttpResponse();
156                $request  = new HttpRequest(new HttpUri(''));
157
158                $request->header->account = 1;
159                $request->setData('title', $l11n);
160                $request->setData('language', $language);
161                $request->setData('type', $billAttrType[$attribute['name']]['id']);
162
163                $module->apiBillAttributeTypeL11nCreate($request, $response);
164            }
165        }
166
167        return $billAttrType;
168    }
169
170    /**
171     * Create default attribute values for types
172     *
173     * @param ApplicationAbstract                                                                                                                                                              $app          Application
174     * @param array                                                                                                                                                                            $billAttrType Attribute types
175     * @param array<array{name:string, l11n?:array<string, string>, is_required?:bool, is_custom_allowed?:bool, validation_pattern?:string, value_type?:string, values?:array<string, mixed>}> $attributes   Attribute definition
176     *
177     * @return array<string, array>
178     *
179     * @since 1.0.0
180     */
181    private static function createBillAttributeValues(ApplicationAbstract $app, array $billAttrType, array $attributes) : array
182    {
183        /** @var array<string, array> $billAttrValue */
184        $billAttrValue = [];
185
186        /** @var \Modules\Billing\Controller\ApiController $module */
187        $module = $app->moduleManager->getModuleInstance('Billing');
188
189        foreach ($attributes as $attribute) {
190            $billAttrValue[$attribute['name']] = [];
191
192            /** @var array $value */
193            foreach ($attribute['values'] as $value) {
194                $response = new HttpResponse();
195                $request  = new HttpRequest(new HttpUri(''));
196
197                $request->header->account = 1;
198                $request->setData('value', $value['value'] ?? '');
199                $request->setData('unit', $value['unit'] ?? '');
200                $request->setData('default', true); // always true since all defined values are possible default values
201                $request->setData('type', $billAttrType[$attribute['name']]['id']);
202
203                if (isset($value['l11n']) && !empty($value['l11n'])) {
204                    $request->setData('title', \reset($value['l11n']));
205                    $request->setData('language', \array_keys($value['l11n'])[0] ?? 'en');
206                }
207
208                $module->apiBillAttributeValueCreate($request, $response);
209
210                $responseData = $response->get('');
211                if (!\is_array($responseData)) {
212                    continue;
213                }
214
215                $attrValue = \is_array($responseData['response'])
216                    ? $responseData['response']
217                    : $responseData['response']->toArray();
218
219                $billAttrValue[$attribute['name']][] = $attrValue;
220
221                $isFirst = true;
222                foreach (($value['l11n'] ?? []) as $language => $l11n) {
223                    if ($isFirst) {
224                        $isFirst = false;
225                        continue;
226                    }
227
228                    $response = new HttpResponse();
229                    $request  = new HttpRequest(new HttpUri(''));
230
231                    $request->header->account = 1;
232                    $request->setData('title', $l11n);
233                    $request->setData('language', $language);
234                    $request->setData('value', $attrValue['id']);
235
236                    $module->apiBillAttributeValueL11nCreate($request, $response);
237                }
238            }
239        }
240
241        return $billAttrValue;
242    }
243
244    /**
245     * Create tax combinations (item & client/supplier)
246     *
247     * @param ApplicationAbstract $app   Application
248     * @param array               $taxes Tax data
249     *
250     * @return array<string, array>
251     *
252     * @since 1.0.0
253     */
254    private static function createTaxCombination(ApplicationAbstract $app, array $taxes) : array
255    {
256        $result = [];
257
258        /** @var \Modules\Billing\Controller\ApiController $module */
259        $module = $app->moduleManager->getModuleInstance('Billing');
260
261        /** @var \Modules\Attribute\Models\AttributeType $itemAttributeSales */
262        $itemAttributeSales = ItemAttributeTypeMapper::get()
263            ->with('defaults')
264            ->where('name', 'sales_tax_code')
265            ->execute();
266
267        /** @var \Modules\Attribute\Models\AttributeType $clientAttributeSales */
268        $clientAttributeSales = ClientAttributeTypeMapper::get()
269            ->with('defaults')
270            ->where('name', 'sales_tax_code')
271            ->execute();
272
273        /** @var \Modules\Attribute\Models\AttributeType $supplierAttributeSales */
274        $supplierAttributeSales = SupplierAttributeTypeMapper::get()
275            ->with('defaults')
276            ->where('name', 'purchase_tax_code')
277            ->execute();
278
279        foreach ($taxes as $tax) {
280            $itemValue    = $itemAttributeSales->getDefaultByValue($tax['item_code']);
281            $accountValue = $tax['type'] === 1
282                ? $clientAttributeSales->getDefaultByValue($tax['account_code'])
283                : $supplierAttributeSales->getDefaultByValue($tax['account_code']);
284
285            $response = new HttpResponse();
286            $request  = new HttpRequest(new HttpUri(''));
287
288            $request->header->account = 1;
289            $request->setData('tax_type', $tax['type']);
290            $request->setData('tax_code', $tax['tax_code']);
291            $request->setData('item_code', $itemValue->id);
292            $request->setData('account_code', $accountValue->id);
293
294            $module->apiTaxCombinationCreate($request, $response);
295
296            $responseData = $response->get('');
297            if (!\is_array($responseData)) {
298                continue;
299            }
300
301            $result = \is_array($responseData['response'])
302                ? $responseData['response']
303                : $responseData['response']->toArray();
304
305            $results[] = $result;
306        }
307
308        return $result;
309    }
310
311    /**
312     * Install default bill types
313     *
314     * @param ApplicationAbstract $app      Application
315     * @param array               $types    Bill types
316     * @param int                 $template Default template
317     *
318     * @return array
319     *
320     * @since 1.0.0
321     */
322    private static function createBillTypes(ApplicationAbstract $app, array $types, int $template) : array
323    {
324        $billTypes = [];
325
326        /** @var \Modules\Billing\Controller\ApiController $module */
327        $module = $app->moduleManager->getModuleInstance('Billing');
328
329        // @todo: allow multiple alternative bill templates
330        // @todo: implement ordering of templates
331
332        foreach ($types as $type) {
333            $response = new HttpResponse();
334            $request  = new HttpRequest(new HttpUri(''));
335
336            $request->header->account = 1;
337            $request->setData('name', $type['name'] ?? '');
338            $request->setData('title', \reset($type['l11n']));
339            $request->setData('language', \array_keys($type['l11n'])[0] ?? 'en');
340            $request->setData('number_format', $type['numberFormat'] ?? '{id}');
341            $request->setData('transfer_stock', $type['transferStock'] ?? false);
342            $request->setData('is_template', $type['isTemplate'] ?? false);
343            $request->setData('transfer_type', $type['transferType'] ?? BillTransferType::SALES);
344            $request->setData('template', $template);
345
346            $module->apiBillTypeCreate($request, $response);
347
348            $responseData = $response->get('');
349            if (!\is_array($responseData)) {
350                continue;
351            }
352
353            $billType = \is_array($responseData['response'])
354                ? $responseData['response']
355                : $responseData['response']->toArray();
356
357            $billTypes[] = $billType;
358
359            $isFirst = true;
360            foreach ($type['l11n'] as $language => $l11n) {
361                if ($isFirst) {
362                    $isFirst = false;
363                    continue;
364                }
365
366                $response = new HttpResponse();
367                $request  = new HttpRequest(new HttpUri(''));
368
369                $request->header->account = 1;
370                $request->setData('title', $l11n);
371                $request->setData('language', $language);
372                $request->setData('type', $billType['id']);
373
374                $module->apiBillTypeL11nCreate($request, $response);
375            }
376        }
377
378        return $billTypes;
379    }
380}