Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
LinkAutomaticWithInvoiceItemService
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 9
272
0.00% covered (danger)
0.00%
0 / 1
 linkAutomatic
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
12
 fetchPurchaseOrder
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 findPurchaseOrderByNumOcp
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 fetchPurchaseOrderItem
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 updateStatusPurchaseOrder
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 updateInvoiceItemStatus
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 processAmount
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 getConversion
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 processActivetyLog
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Domain\PurchaseOrder\Services;
4
5use App\Events\ServiceProcessed;
6use App\Jobs\Senior\SeniorSyncPurchaseOrderJob;
7use App\Models\Conversion\Conversion;
8use App\Models\Invoice\{
9    Invoice,
10    InvoiceItem
11};
12use App\Models\PurchaseOrder\{
13    PurchaseOrder,
14    PurchaseOrderInvoiceItem,
15    PurchaseOrderItem
16};
17use App\Models\UnitMeasurement\UnitMeasurement;
18use App\Models\User;
19use Domain\Conversion\Enums\ConversionTypeEnum;
20use Domain\Invoice\DTOs\StoreInvoiceActivityLogDTO;
21use Domain\Invoice\Enums\InvoiceActivetyLogOperationEnum;
22use Domain\Invoice\Enums\InvoiceItemStatusEnum;
23use Domain\Invoice\Enums\InvoicePurchaseOrderStatusEnum;
24use Domain\Invoice\Exceptions\InvoiceItemAmountExceedException;
25use Domain\Invoice\Services\InvoiceActivityLogStoreService;
26use Domain\PurchaseOrder\DTOs\SeniorPurchaseOrderImportDTO;
27use Domain\PurchaseOrder\Enums\PurchaseOrderInvoiceItemStatusEnum;
28use Domain\Shared\Integrations\Senior\SeniorPurchaseOrderImport;
29use Illuminate\Database\Eloquent\Builder;
30use Illuminate\Support\Facades\DB;
31use Throwable;
32
33readonly class LinkAutomaticWithInvoiceItemService
34{
35    /**
36     * @param InvoiceItem $invoiceItem
37     * @param Invoice $invoice
38     * @param string $key
39     * @param string $numocp
40     * @param string $seqipc
41     * @param User $user
42     * @throws Throwable
43     */
44    public function linkAutomatic(InvoiceItem $invoiceItem, Invoice $invoice, string $key, string $numocp, string $seqipc, User $user): void
45    {
46        $purchaseOrderItem = $this->fetchPurchaseOrderItem($numocp, $seqipc, $key);
47
48        if($purchaseOrderItem){
49            try {
50                DB::beginTransaction();
51
52                $purchaseOrderInvoiceItem = (new PurchaseOrderInvoiceItem());
53                $purchaseOrderInvoiceItem->invoiceItem()->associate($invoiceItem);
54                $purchaseOrderInvoiceItem->purchaseOrderItem()->associate($purchaseOrderItem);
55                $purchaseOrderInvoiceItem->setAttribute('status', PurchaseOrderInvoiceItemStatusEnum::AUTOMATIC);
56
57                $purchaseOrderInvoiceItem->setAttribute('amount', $this->processAmount($purchaseOrderItem, $invoiceItem));
58
59                $purchaseOrderInvoiceItem->save();
60
61                $this->updateStatusPurchaseOrder($invoice, $user);
62                $this->updateInvoiceItemStatus($invoiceItem);
63
64                $this->processActivetyLog(
65                    $invoice,
66                    $user,
67                    PurchaseOrderInvoiceItem::class,
68                    $purchaseOrderInvoiceItem->getKey(),
69                    InvoiceActivetyLogOperationEnum::INSERT,
70                    $purchaseOrderInvoiceItem->getAttributes(),
71                    'Realizado automaticamente o vínculo do item da nota fiscal, com o item da ordem de compra.'
72                );
73
74                DB::commit();
75            } catch (Throwable $exception) {
76                DB::rollBack();
77                throw $exception;
78            }
79        }
80
81        ServiceProcessed::dispatch(self::class, $user);
82    }
83
84    /**
85     * @param string $numocp
86     * @param string $key
87     * @return PurchaseOrder
88     */
89    private function fetchPurchaseOrder(string $numocp, string $key): PurchaseOrder|null
90    {
91        $purchaseOrder = $this->findPurchaseOrderByNumOcp($numocp);
92
93        if (!$purchaseOrder) {
94            $purchaseOrderResults = (new SeniorPurchaseOrderImport())->execute(SeniorPurchaseOrderImportDTO::fromArray([
95                'numocp' => $numocp,
96                'chvnel' => $key
97            ]));
98
99            dispatch_sync(new SeniorSyncPurchaseOrderJob($purchaseOrderResults));
100
101            return $this->findPurchaseOrderByNumOcp($numocp);
102        } else {
103            return $purchaseOrder;
104        }
105    }
106
107    /**
108     * @param string $numocp
109     * @return PurchaseOrder|null
110     */
111    private function findPurchaseOrderByNumOcp(string $numocp): PurchaseOrder|null
112    {
113        return PurchaseOrder::whereHas('integration', function (Builder $query) use ($numocp) {
114                $query->where('parameters->NUMOCP', $numocp);
115            })->first();
116    }
117
118    /**
119     * @param string $numocp
120     * @return PurchaseOrderItem|null
121     */
122    private function fetchPurchaseOrderItem(string $numocp, string $seqipc, string $key): PurchaseOrderItem|null
123    {
124        $purchaseOrder = $this->fetchPurchaseOrder($numocp, $key);
125
126        if($purchaseOrder){
127            return PurchaseOrderItem::where('purchase_order_id', $purchaseOrder->getKey())
128                ->whereHas('integration', function (Builder $query) use ($seqipc) {
129                    $query->where('parameters->SEQIPO', $seqipc);
130                })->first();
131        } else {
132            return null;
133        }
134    }
135
136    /**
137     * @param Invoice $invoice
138     * @param User $user
139     */
140    private function updateStatusPurchaseOrder(Invoice $invoice, User $user)
141    {
142        $invoiceOld = $invoice->getAttributes();
143
144        $invoice->setAttribute('purchase_order_status', InvoicePurchaseOrderStatusEnum::AUTOMATIC);
145        $invoice->save();
146
147        $this->processActivetyLog(
148            $invoice,
149            $user,
150            Invoice::class,
151            $invoice->getKey(),
152            InvoiceActivetyLogOperationEnum::UPDATE,
153            $invoiceOld,
154            'Alterado situação da nota fiscal ao realizar o vínculo automático dos itens.'
155        );
156    }
157
158    /**
159     * @param InvoiceItem $invoiceItem
160     */
161    private function updateInvoiceItemStatus(InvoiceItem $invoiceItem)
162    {
163        $invoiceItem->setAttribute('status', InvoiceItemStatusEnum::AUTOMATIC);
164        $invoiceItem->save();
165    }
166
167    /**
168     * @param PurchaseOrderItem $purchaseOrderItem
169     * @param InvoiceItem $invoiceItem,
170     * @return float
171     */
172    private function processAmount(
173        PurchaseOrderItem $purchaseOrderItem,
174        InvoiceItem $invoiceItem): float
175    {
176        if($invoiceItem->unitMeasurement <> $purchaseOrderItem->product->unitMeasurement){
177            $conversion = $this->getConversion($invoiceItem->unitMeasurement, $purchaseOrderItem->product->unitMeasurement);
178
179            if($conversion){
180                if($conversion->getAttribute('type') == ConversionTypeEnum::MULTIPLY){
181                    $amount = $invoiceItem->getAmount() * $conversion->getAttribute('value');
182                } else {
183                    $amount = $invoiceItem->getAmount() / $conversion->getAttribute('value');
184                }
185            } else {
186                $amount = 0;
187            }
188        } else {
189            $amount = $invoiceItem->getAmount();
190        }
191
192        return $amount;
193    }
194
195    /**
196     * @param UnitMeasurement $unitMFrom
197     * @param UnitMeasurement $unitMTo
198     * @return Conversion|null
199     */
200    private function getConversion(UnitMeasurement $unitMFrom, UnitMeasurement $unitMTo): Conversion|null
201    {
202        return Conversion::where('unit_measurement_from_id', $unitMFrom->getKey())
203            ->where('unit_measurement_to_id', $unitMTo->getKey())
204            ->first();
205    }
206
207    /**
208     * @param Invoice $invoice
209     * @param User $user
210     * @param string $entityType
211     * @param int $entityID
212     * @param InvoiceActivetyLogOperationEnum $operation
213     * @param array $details
214     * @param string $observation
215     */
216    private function processActivetyLog(
217        Invoice $invoice,
218        User $user,
219        string $entityType,
220        int $entityID,
221        InvoiceActivetyLogOperationEnum $operation,
222        array $details,
223        string $observation)
224    {
225        $invoiceActivityLogDTO = new StoreInvoiceActivityLogDTO([
226            'entity_type' => $entityType,
227            'entity_id'   => $entityID,
228            'operation'   => $operation,
229            'user'        => $user,
230            'detail'      => json_encode($details),
231            'observation' => $observation
232        ]);
233
234        (new InvoiceActivityLogStoreService())->store($invoiceActivityLogDTO, $invoice, $user);
235    }
236}