Passed
Push — master ( 952446...f0a3f9 )
by Thomas
07:48 queued 11s
created

InvoiceCrudController::show()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 10
nc 2
nop 1
dl 0
loc 15
rs 9.9332
c 1
b 0
f 1
1
<?php
2
3
namespace App\Http\Controllers\Admin;
4
5
use App\Http\Requests\InvoiceRequest;
6
use App\Models\Invoice;
7
use App\Models\Paymentmethod;
8
use Backpack\CRUD\app\Http\Controllers\CrudController;
9
use Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
10
use Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
11
use Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
12
use Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
13
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
14
use Carbon\Carbon;
15
16
class InvoiceCrudController extends CrudController
17
{
18
    use ListOperation;
0 ignored issues
show
introduced by
The trait Backpack\CRUD\app\Http\C...perations\ListOperation requires some properties which are not provided by App\Http\Controllers\Admin\InvoiceCrudController: $model, $query, $entity_name_plural
Loading history...
19
    use UpdateOperation { update as traitUpdate; }
0 ignored issues
show
introduced by
The trait Backpack\CRUD\app\Http\C...rations\UpdateOperation requires some properties which are not provided by App\Http\Controllers\Admin\InvoiceCrudController: $entity_name, $model
Loading history...
20
    use DeleteOperation;
21
    use ShowOperation { show as traitShow; }
0 ignored issues
show
introduced by
The trait Backpack\CRUD\app\Http\C...perations\ShowOperation requires some properties which are not provided by App\Http\Controllers\Admin\InvoiceCrudController: $route, $entity_name
Loading history...
22
23
    private array $currency;
24
25
    /**
26
     * Configure the CrudPanel object. Apply settings to all operations.
27
     *
28
     * @return void
29
     */
30
    public function setup()
31
    {
32
        CRUD::setModel(Invoice::class);
33
        CRUD::setRoute(config('backpack.base.route_prefix').'/invoice');
34
        CRUD::setEntityNameStrings(__('invoice'), __('invoices'));
35
        if (! config('invoicing.price_categories_enabled')) {
36
            $this->crud->addButtonFromView('top', 'createInvoice', 'createInvoice', 'start');
37
        }
38
39
        if (config('app.currency_position') === 'before') {
40
            $this->currency = ['prefix' => config('app.currency_symbol')];
41
        } else {
42
            $this->currency = ['suffix' => config('app.currency_symbol')];
43
        }
44
    }
45
46
    /**
47
     * Define what happens when the List operation is loaded.
48
     *
49
     * @see  https://backpackforlaravel.com/docs/crud-operation-list-entries
50
     * @return void
51
     */
52
    protected function setupListOperation()
53
    {
54
        if (config('invoicing.invoice_numbering') === 'manual') {
55
            CRUD::column('receipt_number');
56
        } else {
57
            CRUD::column('invoice_number');
58
59
            CRUD::addColumn([
60
                'name' => 'invoiceType',
61
                'type' => 'relationship',
62
                'label' => __('Type'),
63
                'searchLogic' => false,
64
                'attribute' => 'name',
65
            ]);
66
        }
67
68
        $this->crud->addColumn([
69
            'name' => 'created_at',
70
            'key' => 'year',
71
            'label' => __('Year'),
72
            'type' => 'date',
73
            'format' => 'Y',
74
        ]);
75
76
        $this->crud->addColumn([
77
            'name' => 'created_at',
78
            'key' => 'date',
79
            'label' => __('Date'),
80
            'type' => 'date',
81
        ]);
82
83
        CRUD::column('client_name')->label(__('Client name'));
84
        CRUD::column('client_idnumber')->label(__('Client ID Number'));
85
        CRUD::column('client_address')->label(__('Client address'));
86
        CRUD::column('client_email')->label(__('Client email'));
87
        $this->crud->addColumn(
88
            array_merge([
89
                'label' => __('Total price'),
90
                'type' => 'model_function',
91
                'function_name' => 'totalPrice',
92
            ], $this->currency)
93
        );
94
95
        $this->crud->addColumn(
96
            array_merge([
97
                'name' => 'balance',
98
                'label' => __('Remaining balance'),
99
                'type' => 'number',
100
            ], $this->currency)
101
        );
102
103
        CRUD::addFilter(
104
            [
105
                'type' => 'date_range',
106
                'name' => 'from_to',
107
                'label' => __('Date range'),
108
            ],
109
            false,
110
            function ($value) { // if the filter is active, apply these constraints
111
                $dates = json_decode($value, null, 512, JSON_THROW_ON_ERROR);
112
113
                if ($dates->from) {
114
                    CRUD::addClause('where', 'date', '>=', $dates->from);
115
                }
116
                if ($dates->to) {
117
                    CRUD::addClause('where', 'date', '<=', $dates->to.' 23:59:59');
118
                }
119
            }
120
        );
121
    }
122
123
    protected function setupUpdateOperation()
124
    {
125
        CRUD::setValidation(InvoiceRequest::class);
126
127
        CRUD::field('date')->label(__('Date'))->tab(__('Invoice'));
128
129
        if (config('invoicing.invoice_numbering') === 'manual') {
130
            CRUD::field('receipt_number')->tab(__('Invoice'));
131
        } else {
132
            CRUD::field('invoice_number')->tab(__('Invoice'));
133
134
            CRUD::addField([
135
                'name' => 'invoiceType',
136
                'type' => 'relationship',
137
                'label' => 'Type',
138
                'searchLogic' => false,
139
                'attribute' => 'name',
140
                'tab' => __('Invoice'),
141
            ]);
142
        }
143
144
        CRUD::field('client_name')->label(__('Client name'))->tab(__('Invoice'));
145
        CRUD::field('client_idnumber')->label(__('Client ID Number'))->tab(__('Invoice'));
146
        CRUD::field('client_address')->label(__('Client address'))->tab(__('Invoice'));
147
        CRUD::field('client_email')->label(__('Client email'))->tab(__('Invoice'));
148
149
        CRUD::addField([
150
            'tab' => __('Products'),
151
            'name' => 'alert',
152
            'type' => 'view',
153
            'view' => 'invoices/invoice-editing-alert',
154
        ]);
155
156
        CRUD::addField([
157
            'name' => 'invoiceDetails',
158
            'label' => __('Products'),
159
            'type' => 'repeatable',
160
            'fields' => [
161
                [
162
                    'name' => 'id',
163
                    'type' => 'hidden',
164
                ],
165
                [
166
                    'name' => 'product_name',
167
                    'type' => 'text',
168
                    'label' => __('Product'),
169
                    'wrapper' => ['class' => 'form-group col-md-8'],
170
                ],
171
                [
172
                    'name' => 'quantity',
173
                    'type' => 'number',
174
                    'label' => __('Quantity'),
175
                    'attributes' => ['step' => '0.01', 'min' => 1],
176
                    'wrapper' => ['class' => 'form-group col-md-2'],
177
                ],
178
                array_merge([
179
                    'name' => 'price',
180
                    'type' => 'number',
181
                    'attributes' => ['step' => '0.01'],
182
                    'label' => __('Price'),
183
                    'wrapper' => ['class' => 'form-group col-md-2'],
184
                ], $this->currency),
185
            ],
186
            'tab' => __('Products'),
187
            'init_rows' => 0,
188
        ]);
189
190
        CRUD::addField([
191
            'name' => 'payments',
192
            'label' => __('Payments'),
193
            'type' => 'repeatable',
194
            'fields' => [
195
                [
196
                    'name' => 'id',
197
                    'type' => 'hidden',
198
                ],
199
                [
200
                    'name' => 'payment_method',
201
                    'label' => __('Payment method'),
202
                    'type'        => 'select2_from_array',
203
                    'options'     => Paymentmethod::all()->pluck('name', 'code')->toArray(),
204
                    'allows_null' => false,
205
                    'wrapper' => ['class' => 'form-group col-md-6'],
206
                ],
207
                [
208
                    'name' => 'date',
209
                    'type' => 'date',
210
                    'label' => __('Date'),
211
                    'wrapper' => ['class' => 'form-group col-md-3'],
212
                ],
213
                array_merge([
214
                    'name' => 'value',
215
                    'type' => 'number',
216
                    'attributes' => ['step' => '0.01'],
217
                    'label' => __('Value'),
218
                    'wrapper' => ['class' => 'form-group col-md-3'],
219
                ], $this->currency),
220
                [
221
                    'name' => 'comment',
222
                    'type' => 'text',
223
                    'label' => __('Comment'),
224
                    'wrapper' => ['class' => 'form-group col-md-12'],
225
                ],
226
            ],
227
            'tab' => __('Payments'),
228
            'init_rows' => 0,
229
        ]);
230
    }
231
232
    public function show($id)
233
    {
234
        $invoice = Invoice::findOrFail($id)->load('payments');
235
236
        if (! backpack_user()->can('enrollments.edit')) {
237
            abort(403);
238
        }
239
240
        return view('invoices.show', [
241
            'invoice' => $invoice,
242
            'availablePaymentMethods' => Paymentmethod::all(),
243
            'editable' => true,
244
            'enrollment' => $invoice->enrollments->first()?->product,
245
            'comments' => $invoice->comments,
246
            'afterSuccessUrl' => $invoice->enrollments->count() > 0 ? "/enrollment/{$invoice->enrollments->first()->product_id}/show" : '/invoice', // TODO fix this, an invoice can theoretically contain several enrollments
247
        ]);
248
    }
249
250
    public function update()
251
    {
252
        /** @var Invoice $invoice */
253
        $invoice = $this->crud->getCurrentEntry();
254
        $newInvoiceDetails = collect(json_decode($this->crud->getRequest()->input('invoiceDetails'), null, 512, JSON_THROW_ON_ERROR));
255
        $newPaymentsList = collect(json_decode($this->crud->getRequest()->input('payments'), null, 512, JSON_THROW_ON_ERROR));
256
257
        $this->saveInvoiceDetails($invoice, $newInvoiceDetails);
258
        $this->savePayments($invoice, $newPaymentsList);
259
260
        // update model
261
        $response = $this->traitUpdate();
262
263
        return $response;
264
    }
265
266
    private function saveInvoiceDetails(Invoice $invoice, $newInvoiceDetails)
267
    {
268
        // delete entries that have been removed.
269
        foreach ($invoice->invoiceDetails as $oldInvoiceDetail) {
270
            if ($newInvoiceDetails->where('id', $oldInvoiceDetail->id)->count() === 0) {
271
                $oldInvoiceDetail->delete();
272
            }
273
        }
274
275
        // sync new entries
276
        foreach ($newInvoiceDetails as $invoiceDetail) {
277
            $invoice->invoiceDetails()->updateOrCreate(
278
                ['id' => $invoiceDetail->id],
279
                [
280
                    'product_name' => $invoiceDetail->product_name,
281
                    'price' => $invoiceDetail->price,
282
                    'quantity' => $invoiceDetail->quantity,
283
                ]
284
            );
285
        }
286
    }
287
288
    private function savePayments(Invoice $invoice, $newPayments)
289
    {
290
        // delete entries that have been removed.
291
        foreach ($invoice->payments as $oldPayment) {
292
            if ($newPayments->where('id', $oldPayment->id)->count() === 0) {
293
                $oldPayment->delete();
294
            }
295
        }
296
297
        // sync new entries
298
        foreach ($newPayments as $payment) {
299
            $invoice->payments()->updateOrCreate(
300
                ['id' => $payment->id],
301
                [
302
                    'payment_method' => $payment->payment_method,
303
                    'date' => $payment->date,
304
                    'value' => $payment->value,
305
                    'comment' => $payment->comment,
306
                    'responsable_id' => backpack_user()->id,
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
307
                ]
308
            );
309
        }
310
    }
311
}
312