Passed
Push — develop ( f3eb57...728d57 )
by Septianata
13:03
created

ExchangeConversation::displayCustomerData()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 20
c 0
b 0
f 0
dl 0
loc 35
ccs 0
cts 18
cp 0
rs 9.2888
cc 5
nc 2
nop 2
crap 30
1
<?php
2
3
namespace App\Conversations;
4
5
use App\Enum\OrderStatus as EnumOrderStatus;
6
use App\Models\Configuration;
7
use App\Models\Customer;
8
use App\Models\Denomination;
9
use App\Models\Item;
10
use App\Models\Order;
11
use App\Models\OrderStatus as ModelOrderStatus;
12
use BotMan\BotMan\Messages\Incoming\Answer;
13
use BotMan\BotMan\Messages\Outgoing\Actions\Button;
14
use BotMan\BotMan\Messages\Outgoing\Question;
15
use BotMan\Drivers\Telegram\Extensions\Keyboard;
16
use BotMan\Drivers\Telegram\Extensions\KeyboardButton;
17
use Illuminate\Support\Carbon;
18
use Illuminate\Support\Collection;
19
use Illuminate\Support\Str;
20
21
class ExchangeConversation extends Conversation
22
{
23
    /**
24
     * Start the conversation.
25
     *
26
     * @return $this
27
     */
28
    public function run()
29
    {
30
        if (Order::whereDate('created_at', Carbon::today())->count() >= Configuration::getMaximumOrderPerDay()) {
31
            return $this->sayRenderable('conversations.exchange.alert-exceeded-maximum-order-per-day');
32
        }
33
34
        return $this
35
            ->sayRenderable('conversations.exchange.index')
36
            ->verifyCustomer();
37
    }
38
39
    /**
40
     * Verify if the current customer has been registered or not.
41
     *
42
     * @return $this
43
     */
44
    protected function verifyCustomer()
45
    {
46
        if (!$customer = Customer::retrieveByBotManUser($this->getUser())) {
47
            $username = $this->getUser()->getUsername();
48
            $email = $this->getUserStorage('email');
49
50
            if (!$customer = Customer::retrieveByUsernameAndEmail(compact('username', 'email'))) {
51
                return $this
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->setPreviousConver...CustomerConversation()) targeting App\Conversations\Conver...on::startConversation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->setPreviou...CustomerConversation()) returns the type void which is incompatible with the documented return type App\Conversations\ExchangeConversation.
Loading history...
52
                    ->setPreviousConversation($this)
53
                    ->sayRenderable('conversations.exchange.alert-registration-first')
54
                    ->startConversation(new RegisterCustomerConversation);
55
            }
56
        }
57
58
        return $this->displayCustomerData($customer);
59
    }
60
61
    /**
62
     * Reply with customer data.
63
     *
64
     * @param  \App\Models\Customer  $customer
65
     * @param  string|null  $validationErrorMessage
66
     * @return $this
67
     */
68
    protected function displayCustomerData(Customer $customer, string $validationErrorMessage = null)
69
    {
70
        $this->displayValidationErrorMessage($validationErrorMessage);
71
72
        if (!$this->getPreviousConversation() instanceof static) {
73
            $this->say('<em>Data anda sebelumnya sudah pernah terekam di database kami.</em>');
74
        }
75
76
        $this->destroyUserStorage(forceDestroy: true);
77
78
        $question = Question::create(view('conversations.exchange.confirm-customer_data', compact('customer'))->render())
0 ignored issues
show
Bug introduced by
It seems like view('conversations.exch...('customer'))->render() can also be of type array; however, parameter $text of BotMan\BotMan\Messages\Outgoing\Question::create() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
        $question = Question::create(/** @scrutinizer ignore-type */ view('conversations.exchange.confirm-customer_data', compact('customer'))->render())
Loading history...
79
            ->callbackId('exchange_confirm_customer_data')
80
            ->addButtons([
81
                Button::create(view('conversations.register-customer.reply-customer_data-yes')->render())->value('yes'),
0 ignored issues
show
Bug introduced by
It seems like view('conversations.regi...er_data-yes')->render() can also be of type array; however, parameter $text of BotMan\BotMan\Messages\O...ctions\Button::create() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

81
                Button::create(/** @scrutinizer ignore-type */ view('conversations.register-customer.reply-customer_data-yes')->render())->value('yes'),
Loading history...
82
                Button::create(view('conversations.register-customer.reply-customer_data-no')->render())->value('no'),
83
            ]);
84
85
        return $this->ask($question, next: function (Answer $answer) use ($customer) {
86
            if (!$answer->isInteractiveMessageReply()) {
87
                return;
88
            }
89
90
            if (!in_array($value = $answer->getValue(), ['yes', 'no'])) {
91
                return $this->displayCustomerData($customer, $this->fallbackMessage($answer->getText()));
92
            }
93
94
            if ($value === 'no') {
95
                $this->destroyUserStorage();
96
97
                return $this
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->setPreviousConver...CustomerConversation()) targeting App\Conversations\Conver...on::startConversation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
98
                    ->setPreviousConversation($this)
99
                    ->startConversation(new UpdateCustomerConversation);
100
            }
101
102
            return $this->recordOrder($customer);
103
        });
104
    }
105
106
    /**
107
     * Record customer order data.
108
     *
109
     * @param  \App\Models\Customer  $customer
110
     * @param  string|null  $validationErrorMessage
111
     * @return $this
112
     */
113
    protected function recordOrder(Customer $customer, string $validationErrorMessage = null)
114
    {
115
        $this->displayValidationErrorMessage($validationErrorMessage);
116
117
        $denominations = Denomination::all('id', 'name', 'value');
118
        $keyboard = Keyboard::create(Keyboard::TYPE_INLINE)->resizeKeyboard();
119
120
        foreach ($denominations as $denomination) {
121
            $keyboard->addRow(
122
                KeyboardButton::create(
123
                    view('conversations.exchange.reply-denomination', compact('denomination'))->render()
124
                )->callbackData($denomination->getKey())
125
            );
126
        }
127
128
        $response = $this->reply(
129
            $question = view('conversations.exchange.alert-denomination')->render(),
0 ignored issues
show
Bug introduced by
It seems like $question = view('conver...enomination')->render() can also be of type array; however, parameter $message of App\Conversations\Conversation::reply() does only seem to accept BotMan\BotMan\Messages\O...utgoing\Question|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
            /** @scrutinizer ignore-type */ $question = view('conversations.exchange.alert-denomination')->render(),
Loading history...
130
            $additionalParameters = $keyboard->toArray()
131
        );
132
133
        return $this->getBot()->storeConversation($this, next: function (Answer $answer) use ($response, $customer, $denominations) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getBot()->storeCo... $additionalParameters) targeting BotMan\BotMan\BotMan::storeConversation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
134
            if (!$answer->isInteractiveMessageReply()) {
135
                return;
136
            }
137
138
            $this->deleteTelegramMessageFromResponse($response);
139
140
            /** @var \App\Models\Denomination|null $denomination */
141
            if (!$denominations->contains($answer->getValue()) ||
142
                !$denomination = Denomination::find($answer->getValue())) {
143
                return $this->recordOrder($customer, $this->fallbackMessage($answer->getText()));
144
            }
145
146
            /** @var \App\Models\Order $order */
147
            $order = Order::findOrCreateFromCode($this->getUserStorage('order_code'), $customer, function (Order $order) {
148
                $this->setUserStorage(['order_code' => $order->code]);
149
            });
150
151
            if ($order->item_total > Configuration::getMaximumTotalOrderValue()) {
152
                return $this->confirmOrder($order, 'Maaf, total pesanan anda sudah mencapai batas maksimum');
153
            }
154
155
            /**
156
             * If there is an order's item that has same denomination with the selected one,
157
             * then it will be deleted first before customer continue to record item.
158
             */
159
            if ($item = $order->items()->whereHas('denomination', function ($query) use ($denomination) {
160
                $query->whereKey($denomination->getKey());
161
            })->first('id')) {
162
                $item->delete();
163
            }
164
165
            return $this->recordItem($order, $denomination);
166
        }, question: $question, additionalParameters: $additionalParameters);
167
    }
168
169
    /**
170
     * Record customer item data.
171
     *
172
     * @param  \App\Models\Order  $order
173
     * @param  \App\Models\Denomination  $denomination
174
     * @param  string|null  $validationErrorMessage
175
     * @return $this
176
     */
177
    protected function recordItem(Order $order, Denomination $denomination, string $validationErrorMessage = null)
178
    {
179
        $this->displayValidationErrorMessage($validationErrorMessage);
180
181
        $keyboard = Keyboard::create(Keyboard::TYPE_INLINE)->resizeKeyboard();
182
        $unit = Str::lower($denomination->type->label);
183
184
        collect($denomination->range_order_bundle)->chunk(3)->map(function (Collection $quantities) use ($keyboard, $unit) {
0 ignored issues
show
Unused Code introduced by
The import $unit is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
185
            $keyboard->addRow(...$quantities->map(fn ($quantity) => KeyboardButton::create(
186
                view('conversations.exchange.reply-bundle_quantity-quantity', compact('quantity'))->render()
187
            )->callbackData($quantity))->toArray());
188
        });
189
190
        $keyboard->addRow(
191
            KeyboardButton::create(
192
                view('components.conversations.back', ['text' => 'opsi pilih nominal uang'])->render()
193
            )->callbackData('back_to_denomination_option')
194
        );
195
196
        $response = $this->reply(
197
            $question = view('conversations.exchange.ask-bundle_quantity', compact('denomination'))->render(),
0 ignored issues
show
Bug introduced by
It seems like $question = view('conver...nomination'))->render() can also be of type array; however, parameter $message of App\Conversations\Conversation::reply() does only seem to accept BotMan\BotMan\Messages\O...utgoing\Question|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

197
            /** @scrutinizer ignore-type */ $question = view('conversations.exchange.ask-bundle_quantity', compact('denomination'))->render(),
Loading history...
198
            $additionalParameters = $keyboard->toArray()
199
        );
200
201
        return $this->getBot()->storeConversation($this, next: function (Answer $answer) use ($response, $order, $denomination) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getBot()->storeCo... $additionalParameters) targeting BotMan\BotMan\BotMan::storeConversation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
202
            $this->deleteTelegramMessageFromResponse($response);
203
204
            if ($answer->getValue() === 'back_to_denomination_option') {
205
                return $this->recordOrder($order->getCustomerRelationValue());
206
            }
207
208
            if (!in_array($answer->getValue(), $denomination->range_order_bundle)) {
209
                return $this->recordItem($order, $denomination, trans('validation.between.numeric', [
0 ignored issues
show
Bug introduced by
It seems like trans('validation.betwee...>maximum_order_bundle)) can also be of type array and array; however, parameter $validationErrorMessage of App\Conversations\Exchan...versation::recordItem() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

209
                return $this->recordItem($order, $denomination, /** @scrutinizer ignore-type */ trans('validation.between.numeric', [
Loading history...
210
                    'attribute' => trans('Quantity Per Bundle'),
211
                    'min' => $denomination->minimum_order_bundle,
212
                    'max' => $denomination->maximum_order_bundle,
213
                ]));
214
            }
215
216
            $item = new Item([
217
                'quantity_per_bundle' => $denomination->quantity_per_bundle,
218
                'bundle_quantity' => $answer->getValue(),
219
            ]);
220
221
            $item->setDenominationRelationValue($denomination);
222
223
            $order->items()->save($item);
224
225
            $this->confirmOrder($order);
226
        }, question: $question, additionalParameters: $additionalParameters);
227
    }
228
229
    /**
230
     * Confirm customer order data.
231
     *
232
     * @param  \App\Models\Order  $order
233
     * @param  string|null  $validationErrorMessage
234
     * @return $this
235
     */
236
    protected function confirmOrder(Order $order, string $validationErrorMessage = null)
237
    {
238
        $this->displayValidationErrorMessage($validationErrorMessage);
239
240
        $keyboard = Keyboard::create(Keyboard::TYPE_INLINE)->resizeKeyboard()
241
            ->addRow(KeyboardButton::create(view('conversations.exchange.reply-order-yes')->render())
242
                ->callbackData('update_order_status')
243
            )->addRow(KeyboardButton::create(view('conversations.exchange.reply-order-no-update-item')->render())
244
                ->callbackData('update_item')
245
            )->addRow(KeyboardButton::create(view('conversations.exchange.reply-order-no-recreate-item')->render())
246
                ->callbackData('recreate_item')
247
            );
248
249
        $order->load('customer:id,fullname', 'items.denomination');
250
251
        $responseConfirmOrder = $this->reply(view('conversations.exchange.confirm-order', compact('order'))->render());
0 ignored issues
show
Bug introduced by
It seems like view('conversations.exch...act('order'))->render() can also be of type array; however, parameter $message of App\Conversations\Conversation::reply() does only seem to accept BotMan\BotMan\Messages\O...utgoing\Question|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

251
        $responseConfirmOrder = $this->reply(/** @scrutinizer ignore-type */ view('conversations.exchange.confirm-order', compact('order'))->render());
Loading history...
252
253
        $response = $this->reply(
254
            $question = view('conversations.exchange.ask-order')->render(),
255
            $additionalParameters = $keyboard->toArray()
256
        );
257
258
        return $this->getBot()->storeConversation($this, next: function (Answer $answer) use ($response, $responseConfirmOrder, $order) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getBot()->storeCo... $additionalParameters) targeting BotMan\BotMan\BotMan::storeConversation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
259
            $this->deleteTelegramMessageFromResponse($response);
260
261
            switch ($answer->getValue()) {
262
                case 'update_order_status':
263
                    $order->statuses()->save(ModelOrderStatus::make([
0 ignored issues
show
Bug introduced by
It seems like App\Models\OrderStatus::...ustomerRelationValue()) can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $model of Illuminate\Database\Eloq...ns\HasOneOrMany::save() does only seem to accept Illuminate\Database\Eloquent\Model, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

263
                    $order->statuses()->save(/** @scrutinizer ignore-type */ ModelOrderStatus::make([
Loading history...
264
                        'status' => EnumOrderStatus::on_progress(),
265
                    ])->setIssuerableRelationValue($order->getCustomerRelationValue()));
266
267
                    return $this->sayRenderable('conversations.exchange.alert-update_order_status', compact('order'));
268
269
                case 'update_item':
270
                case 'recreate_item':
271
                    $this->deleteTelegramMessageFromResponse($responseConfirmOrder);
272
273
                    if ($answer->getValue() === 'recreate_item') {
274
                        $order->items->map->delete();
275
                    }
276
277
                    return $this->recordOrder($order->getCustomerRelationValue());
278
279
                default:
280
                    return $this->confirmOrder($order, $this->fallbackMessage($answer->getText()));
281
            }
282
        }, question: $question, additionalParameters: $additionalParameters);
283
    }
284
}
285