diff --git a/resources/views/emails/sales/return/return-approval-request-single.blade.php b/resources/views/emails/sales/return/return-approval-request-single.blade.php
index 846673e76..993227362 100644
--- a/resources/views/emails/sales/return/return-approval-request-single.blade.php
+++ b/resources/views/emails/sales/return/return-approval-request-single.blade.php
@@ -138,13 +138,13 @@
Check
Approve
Reject
diff --git a/resources/views/emails/sales/return/return-approval-request.blade.php b/resources/views/emails/sales/return/return-approval-request.blade.php
index 862e811c3..5e427af0f 100644
--- a/resources/views/emails/sales/return/return-approval-request.blade.php
+++ b/resources/views/emails/sales/return/return-approval-request.blade.php
@@ -48,15 +48,8 @@
Form Number |
Form Reference |
Customer |
-
-
-
- | Item |
- Quantity Return |
-
-
-
- |
+ Item |
+ Quantity Return |
Note |
Created By |
Created At |
@@ -72,13 +65,13 @@
$urlApprovalQueries['crud-type'] = $salesReturn->action;
@endphp
- |
+ |
{{ $loop->iteration }}
|
-
+ |
{{ date('d M Y', strtotime($salesReturnForm->date)) }}
|
-
+ |
{{ $salesReturnForm->number }}
{{ ' ' }}
{{
@@ -88,41 +81,32 @@
: ''
}}
|
-
+ |
{{ $salesReturn->salesInvoice->form->number }}
|
-
+ |
{{ $salesReturn->customer->name }}
|
-
-
-
- @foreach($salesReturn->items as $item)
- @php $borderBottom = !$loop->last ? 'border-bottom: 1px solid black' : ''; @endphp
-
- |
- {{ $item->item->name }}
- |
-
- {{ $item->quantity }}
- |
-
-
- @endforeach
-
-
+ @foreach($salesReturn->items as $item)
+ |
+ {{ $item->item->name }}
|
-
- {{ $item->note }}
+ |
+ {{ $item->quantity }}
|
-
+ @break
+ @endforeach
+ |
+ {{ $salesReturnForm->notes }}
+ |
+
{{ $salesReturnForm->createdBy->getFullNameAttribute() }}
|
-
+ |
{{ date('d M Y, H:i', strtotime($salesReturnForm->created_at)) }}
|
-
- |
+ @php
+ ($first = true);
+ @endphp
+ @foreach($salesReturn->items as $item)
+ @if($first)
+ @php
+ ($first = false);
+ @endphp
+ @continue
+ @endif
+
+ |
+ {{ $item->item->name }}
+ |
+
+ {{ $item->quantity }}
+ |
+
+ @endforeach
@endforeach
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalByEmailTest.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalByEmailTest.php
new file mode 100644
index 000000000..20942c4fc
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalByEmailTest.php
@@ -0,0 +1,299 @@
+id)->first();
+ if (!$approverToken) {
+ $approverToken = new Token();
+ $approverToken->user_id = $tenantUser->id;
+ $approverToken->token = md5($tenantUser->email.''.now());
+ $approverToken->save();
+ }
+
+ return $approverToken;
+ }
+ private function changeActingAs($tenantUser, $purchaseReturn)
+ {
+ $tenantUser->branches()->syncWithoutDetaching($purchaseReturn->form->branch_id);
+ foreach ($tenantUser->branches as $branch) {
+ $branch->pivot->is_default = true;
+ $branch->pivot->save();
+ }
+ $tenantUser->warehouses()->syncWithoutDetaching($purchaseReturn->warehouse_id);
+ foreach ($tenantUser->warehouses as $warehouse) {
+ $warehouse->pivot->is_default = true;
+ $warehouse->pivot->save();
+ }
+ $user = new User();
+ $user->id = $tenantUser->id;
+ $user->name = $tenantUser->name;
+ $user->email = $tenantUser->email;
+ $user->save();
+ $this->actingAs($user, 'api');
+ }
+
+ /** @test */
+ public function success_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(204);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchaseReturn->form->number,
+ 'request_cancellation_reason' => $data['reason'],
+ 'cancellation_status' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_approve_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/approve', [], $this->headers);
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 1
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Approved'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_approve_by_email_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $approver = $purchaseReturn->form->requestApprovalTo;
+ $approverToken = $this->findOrCreateToken($approver);
+
+ $this->changeActingAs($approver, $purchaseReturn);
+
+ $data = [
+ 'action' => 'approve',
+ 'approver_id' => $purchaseReturn->form->request_approval_to,
+ 'token' => $approverToken->token,
+ 'resource-type' => 'PurchaseReturn',
+ 'ids' => [
+ ['id' => $purchaseReturn->id]
+ ],
+ 'crud-type' => 'delete'
+ ];
+
+ $response = $this->json('POST', self::$path . '/approve', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $purchaseReturn->form->id,
+ 'number' => $purchaseReturn->form->number,
+ 'approval_status' => 1
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturn->form->number,
+ 'table_id' => $purchaseReturn->id,
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Approved by Email'
+ ], 'tenant');
+ $this->assertDatabaseHas('inventories', [
+ 'form_id' => $purchaseReturn->form->id,
+ 'item_id' => $purchaseReturn->items()->first()->item_id,
+ 'quantity' => $purchaseReturn->items()->first()->quantity,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function unauthorized_approve_by_email_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $this->unsetUserRole();
+
+ $response = $this->json('POST', self::$path . '/approve', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function success_approve_delete_by_email_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $approver = $purchaseReturn->form->requestCancellationTo;
+ $approverToken = $this->findOrCreateToken($approver);
+
+ $this->changeActingAs($approver, $purchaseReturn);
+
+ $data = [
+ 'action' => 'approve',
+ 'approver_id' => $purchaseReturn->form->request_cancellation_to,
+ 'token' => $approverToken->token,
+ 'resource-type' => 'PurchaseReturn',
+ 'ids' => [
+ ['id' => $purchaseReturn->id]
+ ],
+ 'crud-type' => 'delete'
+ ];
+
+ $response = $this->json('POST', self::$path . '/approve', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchaseReturn->form->number,
+ 'cancellation_status' => 1,
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturn->form->number,
+ 'table_id' => $purchaseReturn->id,
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Cancellation Approved by Email'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function unauthorized_reject_by_email_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $this->unsetUserRole();
+
+ $response = $this->json('POST', self::$path . '/reject', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function success_reject_by_email_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $approver = $purchaseReturn->form->requestApprovalTo;
+ $approverToken = $this->findOrCreateToken($approver);
+
+ $this->changeActingAs($approver, $purchaseReturn);
+
+ $data = [
+ 'action' => 'reject',
+ 'approver_id' => $purchaseReturn->form->request_approval_to,
+ 'token' => $approverToken->token,
+ 'resource-type' => 'PurchaseReturn',
+ 'ids' => [
+ ['id' => $purchaseReturn->id]
+ ],
+ 'crud-type' => 'delete'
+ ];
+
+ $response = $this->json('POST', self::$path . '/reject', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $purchaseReturn->form->id,
+ 'number' => $purchaseReturn->form->number,
+ 'approval_status' => -1,
+ 'done' => 0,
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturn->form->number,
+ 'table_id' => $purchaseReturn->id,
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Rejected by Email'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_reject_delete_by_email_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $approver = $purchaseReturn->form->requestCancellationTo;
+ $approverToken = $this->findOrCreateToken($approver);
+
+ $this->changeActingAs($approver, $purchaseReturn);
+
+ $data = [
+ 'action' => 'reject',
+ 'approver_id' => $purchaseReturn->form->request_cancellation_to,
+ 'token' => $approverToken->token,
+ 'resource-type' => 'PurchaseReturn',
+ 'ids' => [
+ ['id' => $purchaseReturn->id]
+ ],
+ 'crud-type' => 'delete'
+ ];
+
+ $response = $this->json('POST', self::$path . '/reject', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchaseReturn->form->number,
+ 'cancellation_status' => -1,
+ 'done' => 0
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturn->form->number,
+ 'table_id' => $purchaseReturn->id,
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Cancellation Rejected by Email'
+ ], 'tenant');
+ }
+}
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalTest.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalTest.php
new file mode 100644
index 000000000..2b2184062
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnApprovalTest.php
@@ -0,0 +1,283 @@
+getDummyData();
+
+ if($isFirstCreate) {
+ $this->setRole();
+ $this->previousPurchaseReturnData = $data;
+ }
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_approve_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/approve', [], $this->headers);
+ $response->assertStatus(200);
+ $subTotal = $response->json('data.amount') - $response->json('data.tax');
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 1
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Approved'
+ ], 'tenant');
+ $this->assertDatabaseHas('journals', [
+ 'form_id' => $response->json('data.form.id'),
+ 'chart_of_account_id' => $this->apCoa->id
+ ], 'tenant');
+ $this->assertDatabaseHas('journals', [
+ 'form_id' => $response->json('data.form.id'),
+ 'chart_of_account_id' => $this->taxCoa->id
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function error_form_already_approved_approve_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturn->form->approval_status = 1;
+ $purchaseReturn->form->save();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/approve', [], $this->headers);
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Can't approve, form already approved!"
+ ]);
+ }
+
+ /** @test */
+ public function error_unauthorized_approve_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/approve', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_no_reason_reject_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/reject', [], $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "The given data was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_reason_more_than_255_character_reject_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(300);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/reject', [], $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Reason can\t more than 255 character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_unauthorized_reject_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/reject', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function success_reject_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/reject', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => -1,
+ 'done' => 0,
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Rejected'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function read_all_purchase_return_approval()
+ {
+
+ $this->success_create_purchase_return();
+ $purchaseReturn = PurchaseReturn::whereHas('form', function($query){
+ $query->whereApprovalStatus(0);
+ })->get();
+
+ $purchaseReturn = $purchaseReturn->sortByDesc(function($q){
+ return $q->form->date;
+ });
+
+ $response = $this->json('GET', self::$path . '/approval', [
+ 'limit' => '10',
+ 'page' => '1',
+ ], $this->headers);
+
+ $data = [];
+ foreach ($purchaseReturn as $pReturn) {
+ $items = [];
+ foreach ($pReturn->items as $item) {
+ array_push($items, [
+ "id" => $item->id,
+ "purchase_return_id" => $item->purchase_return_id,
+ "purchase_invoice_item_id" => $item->purchase_invoice_item_id,
+ "item_id" => $item->item_id,
+ "quantity" => $item->quantity,
+ "unit" => $item->unit,
+ "converter" => $item->converter,
+ ]);
+ }
+ array_push($data, [
+ "id" => $pReturn->id,
+ "supplier_id" => $pReturn->supplier_id,
+ "supplier_name" => $pReturn->supplier_name,
+ "date" => $pReturn->form->date,
+ "number" => $pReturn->form->number,
+ "notes" => $pReturn->form->notes,
+ "items" => $items
+ ]);
+ };
+
+ $response->assertStatus(200)
+ ->assertJson([
+ "data" => $data,
+ "links" => [
+ "prev" => null,
+ "next" => null
+ ],
+ "meta" => [
+ "total" => count($purchaseReturn)
+ ]
+ ]);
+ }
+
+ /** @test */
+ public function success_send_approval_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data = [
+ "ids" => [
+ "id" => $purchaseReturn->id,
+ ],
+ ];
+
+ $response = $this->json('POST', self::$path.'/approval/send', $data, $this->headers);
+
+ $response->assertStatus(200)
+ ->assertJson([
+ "input" => [
+ "ids" => [
+ "id" => $memoJournal->id,
+ ]
+ ]
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_send_approval_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetBranch();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data = [
+ "ids" => [
+ "id" => $purchaseReturn->id,
+ ],
+ ];
+
+ $response = $this->json('POST', self::$path.'/approval/send', $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to create this form"
+ ]);
+ $this->setBranch();
+ }
+}
\ No newline at end of file
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnCancellationApprovalTest.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnCancellationApprovalTest.php
new file mode 100644
index 000000000..9edde070f
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnCancellationApprovalTest.php
@@ -0,0 +1,184 @@
+setRole();
+
+ $data = $this->getDummyData();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchasesReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchasesReturn->id, $data, $this->headers);
+
+ $response->assertStatus(204);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchasesReturn->form->number,
+ 'request_cancellation_reason' => $data['reason'],
+ 'cancellation_status' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_cancellation_approve_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchasesReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchasesReturn->id . '/cancellation-approve', [], $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchasesReturn->form->number,
+ 'cancellation_status' => 1,
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Cancel Approved'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function error_already_approved_cancellation_approve_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchasesReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchasesReturn->form->cancellation_status = 1;
+ $purchasesReturn->form->save();
+
+ $response = $this->json('POST', self::$path . '/' . $purchasesReturn->id . '/cancellation-approve', [], $this->headers);
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Can't approve, form already cancelled!"
+ ]);
+ }
+
+ /** @test */
+ public function success_reject_cancellation_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/cancellation-reject', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => -1,
+ 'done' => 0,
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Rejected'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function error_no_reason_reject_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/cancellation-reject', [], $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "The given data was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_reason_more_than_255_character_reject_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(300);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/cancellation-reject', [], $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Reason can\t more than 255 character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_unauthorized_approve_cancellation_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/cancellation-approve', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_unauthorized_reject_cancellation_purchase_return()
+ {
+ $this->success_delete_purchase_return();
+
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/cancellation-reject', [], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `approve purchase return` for guard `api`."
+ ]);
+ }
+}
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnHistoryTest.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnHistoryTest.php
new file mode 100644
index 000000000..a2c42ae46
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnHistoryTest.php
@@ -0,0 +1,167 @@
+setRole();
+
+ $data = $this->getDummyData();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData($purchaseReturn);
+ $data = data_set($data, 'id', $purchaseReturn->id, false);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [ 'edited_number' => $response->json('data.form.number') ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Update - 1'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function read_purchase_return_histories()
+ {
+ $this->success_update_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturnUpdated = PurchaseReturn::orderBy('id', 'desc')->first();
+
+ $data = [
+ 'sort_by' => '-user_activities.date',
+ 'includes' => 'user',
+ 'filter_like' => '{}',
+ 'or_filter_where_has_like[]' => '{"user":{}}',
+ 'limit' => 10,
+ 'page' => 1
+ ];
+
+ $response = $this->json('GET', self::$path . '/' . $purchaseReturnUpdated->id . '/histories', $data, $this->headers);
+
+ $response->assertStatus(200);
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturn->form->edited_number,
+ 'table_id' => $purchaseReturn->id,
+ 'table_type' => $purchaseReturn::$morphName,
+ 'activity' => 'Created'
+ ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $purchaseReturnUpdated->form->number,
+ 'table_id' => $purchaseReturnUpdated->id,
+ 'table_type' => $purchaseReturnUpdated::$morphName,
+ 'activity' => 'Update - 1'
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function success_create_purchase_return_history()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data = [
+ "id" => $purchaseReturn->id,
+ "activity" => "Printed"
+ ];
+
+ $response = $this->json('POST', self::$path . '/' . $purchaseReturn->id . '/histories', $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.number'),
+ 'table_id' => $response->json('data.table_id'),
+ 'table_type' => $response->json('data.table_type'),
+ 'activity' => $response->json('data.activity')
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function unauthorized_read_purchase_return_history()
+ {
+
+ $this->success_update_purchase_return();
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturnUpdated = PurchaseReturn::orderBy('id', 'desc')->first();
+
+ $data = [
+ 'sort_by' => '-user_activities.date',
+ 'includes' => 'user',
+ 'filter_like' => '{}',
+ 'or_filter_where_has_like[]' => '{"user":{}}',
+ 'limit' => 10,
+ 'page' => 1
+ ];
+
+ $response = $this->json('GET', self::$path . '/' . $purchaseReturnUpdated->id . '/histories', $data, $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `read purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_read_purchase_return_history()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetBranch();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturnUpdated = PurchaseReturn::orderBy('id', 'desc')->first();
+
+ $data = [
+ 'sort_by' => '-user_activities.date',
+ 'includes' => 'user',
+ 'filter_like' => '{}',
+ 'or_filter_where_has_like[]' => '{"user":{}}',
+ 'limit' => 10,
+ 'page' => 1
+ ];
+
+ $response = $this->json('GET', self::$path . '/' . $purchaseReturnUpdated->id . '/histories', $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to read this form"
+ ]);
+ $this->setBranch();
+ }
+}
\ No newline at end of file
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnSetup.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnSetup.php
new file mode 100644
index 000000000..16008f777
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnSetup.php
@@ -0,0 +1,431 @@
+signIn();
+ $this->setProject();
+
+ $this->tenantUser = TenantUser::find($this->user->id);
+ $this->branchDefault = $this->tenantUser->branches()
+ ->where('is_default', true)
+ ->first();
+
+ $this->createSupplierUnitItem();
+ $this->setUserWarehouse($this->branchDefault);
+ $this->setApprover();
+ }
+
+ private function setUserWarehouse($branch = null)
+ {
+ $warehouse = $this->createWarehouse($branch);
+ $this->tenantUser->warehouses()->syncWithoutDetaching($warehouse->id);
+ foreach ($this->tenantUser->warehouses as $warehouse) {
+ $warehouse->pivot->is_default = true;
+ $warehouse->pivot->save();
+
+ $this->warehouseSelected = $warehouse;
+ }
+ }
+
+ protected function unsetUserRole()
+ {
+ $role = Role::createIfNotExists('super admin');
+
+ ModelHasRole::where('role_id', $role->id)
+ ->where('model_type', 'App\Model\Master\User')
+ ->where('model_id', $this->user->id)
+ ->delete();
+ }
+
+ private function unsetBranch()
+ {
+ foreach ($this->tenantUser->branches as $branch) {
+ $branch->pivot->is_default = false;
+ $branch->pivot->save();
+ }
+ }
+
+ private function setBranch()
+ {
+ foreach ($this->tenantUser->branches as $branch) {
+ $branch->pivot->is_default = true;
+ $branch->pivot->save();
+ }
+ }
+
+ private function createWarehouse($branch = null)
+ {
+ $warehouse = new Warehouse();
+ $warehouse->name = 'Test warehouse';
+
+ if($branch) $warehouse->branch_id = $branch->id;
+
+ $warehouse->save();
+
+ return $warehouse;
+ }
+
+ private function createSupplierUnitItem()
+ {
+ $this->supplier = factory(Supplier::class)->create();
+ $this->unit = factory(ItemUnit::class)->make();
+ $this->item = factory(Item::class)->create();
+ $this->item->units()->save($this->unit);
+
+ $this->generateChartOfAccount();
+ $this->item->chart_of_account_id = $this->coa->id;
+ $this->item->save();
+ }
+
+ private function setApprover()
+ {
+ $role = Role::createIfNotExists('super admin');
+ $this->approver = factory(TenantUser::class)->create();
+ $this->approver->assignRole($role);
+ }
+
+ private function generateChartOfAccount()
+ {
+ $coa = ChartOfAccount::where('name', 'FINISHED GOOD INVENTORY')->first();
+ if ($coa) {
+ $this->coa = $coa;
+ } else {
+ $type = new ChartOfAccountType;
+ $type->name = 'INVENTORY';
+ $type->alias = 'PERSEDIAAN';
+ $type->is_debit = 1;
+ $type->save();
+
+ $this->coa = new ChartOfAccount;
+ $this->coa->type_id = $type->id;
+ $this->coa->position = 'DEBIT';
+ $this->coa->is_locked = 1;
+ $this->coa->number = 11601;
+ $this->coa->name = 'FINISHED GOOD INVENTORY';
+ $this->coa->alias = 'PERSEDIAAN BARANG JADI ';
+ $this->coa->created_by = $this->user->id;
+ $this->coa->updated_by = $this->user->id;
+ $this->coa->save();
+ error_log('haha');
+ }
+
+ $apCoaJournal = SettingJournal::where('feature', 'purchase')->where('name', 'account payable')->first();
+ if ($apCoaJournal) {
+ $apCoa = ChartOfAccount::where('id', $apCoaJournal->chart_of_account_id)->first();
+ $this->apCoa = $apCoa;
+ } else {
+ $type = new ChartOfAccountType;
+ $type->name = 'ACCOUNT PAYABLE';
+ $type->alias = 'HUTANG USAHA';
+ $type->is_debit = 0;
+ $type->save();
+
+ $this->apCoa = new ChartOfAccount;
+ $this->apCoa->type_id = $type->id;
+ $this->apCoa->position = 'CREDIT';
+ $this->apCoa->is_locked = 1;
+ $this->apCoa->number = 21201;
+ $this->apCoa->name = 'ACCOUNT PAYABLE';
+ $this->apCoa->alias = 'HUTANG DAGANG';
+ $this->apCoa->created_by = $this->user->id;
+ $this->apCoa->updated_by = $this->user->id;
+ $this->apCoa->save();
+
+ $setting = new SettingJournal;
+ $setting->feature = 'purchase';
+ $setting->name = 'account payable';
+ $setting->chart_of_account_id = $this->apCoa->id;
+ $setting->save();
+ }
+
+ $taxCoaJournal = SettingJournal::where('feature', 'purchase')->where('name', 'income tax receivable')->first();
+ if ($taxCoaJournal) {
+ $taxCoa = ChartOfAccount::where('id', $taxCoaJournal->chart_of_account_id)->first();
+ $this->taxCoa = $taxCoa;
+ } else {
+ $type = new ChartOfAccountType;
+ $type->name = 'INCOME TAX RECEIVABLE';
+ $type->alias = 'PPN MASUKAN';
+ $type->is_debit = 1;
+ $type->save();
+
+ $this->taxCoa = new ChartOfAccount;
+ $this->taxCoa->type_id = $type->id;
+ $this->taxCoa->position = 'DEBIT';
+ $this->taxCoa->is_locked = 1;
+ $this->taxCoa->number = 11707;
+ $this->taxCoa->name = 'INCOME TAX RECEIVABLE ';
+ $this->taxCoa->alias = 'PPN MASUKAN';
+ $this->taxCoa->created_by = $this->user->id;
+ $this->taxCoa->updated_by = $this->user->id;
+ $this->taxCoa->save();
+
+ $setting = new SettingJournal;
+ $setting->feature = 'purchase';
+ $setting->name = 'income tax receivable';
+ $setting->chart_of_account_id = $this->taxCoa->id;
+ $setting->save();
+ }
+ }
+
+ private function getDummyData($purchaseReturn = null)
+ {
+ $inv = $purchaseReturn ?? $this->createPurchaseInvoice();
+
+ $invoice = $purchaseReturn ? $inv->purchaseInvoice : $inv;
+ $invoiceItem = $invoice->items()->first();
+
+ $quantityInvoice = $invoiceItem->quantity;
+ $quantityReturned = 0;
+ foreach ($invoiceItem->returnItem as $returnItem) {
+ $quantityReturned += $returnItem->quantity;
+ }
+
+ $supplier = $invoice->supplier;
+ $approver = $invoice->form->requestApprovalTo;
+
+ return [
+ 'increment_group' => date('Ym'),
+ 'date' => date('Y-m-d H:i:s'),
+ 'purchase_invoice_id' => $invoice->id,
+ "warehouse_id" => $invoiceItem->purchaseReceive->warehouse_id,
+ 'supplier_id' => $supplier->id,
+ 'supplier_name' => $supplier->name,
+ 'supplier_address' => null,
+ 'supplier_phone' => null,
+ 'tax' => 1500,
+ 'amount' => 15000,
+ 'notes' => null,
+ 'items' => [
+ [
+ 'purchase_invoice_item_id' => $invoiceItem->id,
+ 'item_id' => $this->item->id,
+ 'item_name' => $this->item->name,
+ 'item_label' => "[{$this->item->code}] - {$this->item->name}",
+ 'unit' => $this->unit->label,
+ 'converter' => $invoiceItem->converter,
+ 'quantity' => 3,
+ 'price' => $invoiceItem->price,
+ 'discount_percent' => $invoiceItem->discount_percent,
+ 'discount_value' => $invoiceItem->discount_value,
+ 'notes' => null,
+ ],
+ ],
+ 'request_approval_to' => $approver->id,
+ 'approver_name' => $approver->name,
+ 'approver_email' => $approver->email,
+ ];
+ }
+
+ private function createPurchaseOrder()
+ {
+ $params = [
+ 'increment_group' => date('Ym'),
+ 'date' => date('Y-m-d H:i:s'),
+ 'supplier_id' => $this->supplier->id,
+ 'supplier_name' => $this->supplier->name,
+ 'supplier_label' => $this->supplier->code,
+ 'supplier_address' => $this->supplier->address,
+ 'supplier_phone' => $this->supplier->phone,
+ 'supplier_email' => $this->supplier->phone,
+ 'need_down_payment' => 0,
+ 'cash_only' => false,
+ 'notes' => null,
+ 'discount_percent' => 0,
+ 'discount_value' => 0,
+ 'tax_base' => 1100000,
+ 'tax' => 110000,
+ 'type_of_tax' => 'exclude',
+ 'items' => [
+ [
+ 'purchase_request_item_id' => null,
+ 'item_id' => $this->item->id,
+ 'item_name' => $this->item->name,
+ 'more' => false,
+ 'unit' => $this->unit->label,
+ 'converter' => 1,
+ 'quantity' => '220',
+ 'price' => 5000,
+ 'discount_percent' => 0,
+ 'discount_value' => 0,
+ 'allocation_id' => null,
+ 'allocation_name' => '',
+ 'notes' => null,
+ 'item_label' => "[{$this->item->code}] - {$this->item->name}",
+ 'units' => [
+ [
+ 'id' => $this->unit->id,
+ 'label' => $this->unit->label,
+ 'name' => $this->unit->name,
+ 'converter' => 1,
+ 'disabled' => 0,
+ 'item_id' => $this->item->id,
+ 'created_by' => 1,
+ 'updated_by' => 1,
+ 'created_at' => '2022-05-13 10:38:42',
+ 'updated_at' => '2022-05-13 10:38:42',
+ 'prices' => [],
+ ],
+ ],
+ ],
+ ],
+ 'request_approval_to' => $this->approver->id,
+ 'approver_name' => $this->approver->getFullNameAttribute(),
+ 'approver_email' => $this->approver->email,
+ 'purchase_request_id' => null,
+ ];
+
+ $purchaseOrder = PurchaseOrder::create($params);
+ $purchaseOrder->form->approval_by = $this->approver->id;
+ $purchaseOrder->form->approval_at = now();
+ $purchaseOrder->form->approval_status = 1;
+ $purchaseOrder->form->save();
+
+ return $purchaseOrder;
+ }
+
+ private function createPurchaseReceive()
+ {
+ $order = $this->createPurchaseOrder();
+ $orderItem = $order->items()->first();
+
+ $params = [
+ 'increment_group' => date('Ym'),
+ 'purchase_order_id' => $order->id,
+ 'date' => date('Y-m-d H:i:s'),
+ 'warehouse_id' => $this->warehouseSelected->id,
+ 'warehouse_name' => $this->warehouseSelected->name,
+ 'supplier_id' => $this->supplier->id,
+ 'supplier_name' => $this->supplier->name,
+ 'supplier_label' => $this->supplier->code,
+ 'supplier_address' => $this->supplier->address,
+ 'supplier_phone' => $this->supplier->phone,
+ 'driver' => '-',
+ 'license_plate' => '-',
+ 'items' => [
+ [
+ 'id' => $orderItem->id,
+ 'purchase_order_id' => $order->id,
+ 'purchase_request_item_id' => null,
+ 'item_id' => $this->item->id,
+ 'item_name' => $this->item->name,
+ 'unit' => $this->unit->label,
+ 'converter' => 1,
+ 'quantity' => '220',
+ 'price' => 5000,
+ 'discount_percent' => 0,
+ 'discount_value' => 0,
+ 'allocation_id' => null,
+ 'notes' => null,
+ 'purchase_order_item_id' => $orderItem->id,
+ 'item_label' => "[{$this->item->code}] - {$this->item->name}",
+ 'quantity_pending' => '220',
+ 'warehouse_id' => $this->warehouseSelected->id,
+ 'warehouse_name' => $this->warehouseSelected->name,
+ ],
+ ],
+ 'request_approval_to' => $this->approver->id,
+ 'approver_name' => $this->approver->getFullNameAttribute(),
+ 'approver_email' => $this->approver->email,
+ 'purchase_request_id' => null,
+ ];
+
+ $purchaseReceive = PurchaseReceive::create($params);
+ $purchaseReceive->form->approval_by = $this->approver->id;
+ $purchaseReceive->form->approval_at = now();
+ $purchaseReceive->form->approval_status = 1;
+ $purchaseReceive->form->save();
+
+ return $purchaseReceive;
+ }
+
+ private function createPurchaseInvoice()
+ {
+ $receive = $this->createPurchaseReceive();
+ $receiveItem = $receive->items()->first();
+
+ $params = [
+ 'increment_group' => date('Ym'),
+ 'date' => date('Y-m-d H:i:s'),
+ 'due_date' => date('Y-m-d H:i:s'),
+ 'supplier_id' => $this->supplier->id,
+ 'supplier_name' => $this->supplier->name,
+ 'supplier_label' => $this->supplier->code,
+ 'supplier_address' => $this->supplier->address,
+ 'supplier_phone' => $this->supplier->phone,
+ 'supplier_email' => $this->supplier->phone,
+ 'need_down_payment' => 0,
+ 'cash_only' => false,
+ 'notes' => null,
+ 'discount_percent' => 0,
+ 'discount_value' => 0,
+ 'tax_base' => 1100000,
+ 'tax' => 110000,
+ 'type_of_tax' => 'exclude',
+ 'items' => [
+ [
+ 'purchase_receive_id' => $receive->id,
+ 'purchase_receive_item_id' => $receiveItem->id,
+ 'item_id' => $this->item->id,
+ 'item_name' => $this->item->name,
+ 'more' => false,
+ 'unit' => $this->unit->label,
+ 'converter' => 1,
+ 'quantity' => '220',
+ 'price' => 5000,
+ 'discount_percent' => 0,
+ 'discount_value' => 0,
+ 'allocation_id' => null,
+ 'total' => 1100000,
+ 'notes' => null,
+ 'item_label' => "[{$this->item->code}] - {$this->item->name}",
+ ],
+ ],
+ 'request_approval_to' => $this->approver->id,
+ 'approver_name' => $this->approver->getFullNameAttribute(),
+ 'approver_email' => $this->approver->email,
+ 'purchase_request_id' => null,
+ ];
+
+ $purchaseInvoice = PurchaseInvoice::create($params);
+ $purchaseInvoice->form->approval_by = $this->approver->id;
+ $purchaseInvoice->form->approval_at = now();
+ $purchaseInvoice->form->approval_status = 1;
+ $purchaseInvoice->form->save();
+
+ return $purchaseInvoice;
+ }
+}
\ No newline at end of file
diff --git a/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnTest.php b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnTest.php
new file mode 100644
index 000000000..ca28ac9ae
--- /dev/null
+++ b/tests/Feature/Http/Purchase/PurchaseReturn/PurchaseReturnTest.php
@@ -0,0 +1,580 @@
+setRole();
+
+ $data = $this->getDummyData();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+
+ $this->assertDatabaseHas('purchase_returns', [
+ 'id' => $response->json('data.id'),
+ 'supplier_name' => $response->json('data.supplier_name'),
+ 'purchase_invoice_id' => $data->purchase_invoice_id,
+ ], 'tenant');
+
+ $this->assertDatabaseHas('purchase_return_items', [
+ 'purchase_return_id' => $response->json('data.id'),
+ 'item_id' => $data->items[0]->item_id,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function unauthorized_create_purchase_return()
+ {
+ $this->unsetUserRole();
+ $data = $this->getDummyData();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `create purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+
+ $this->unsetBranch();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to create this form"
+ ]);
+ $this->setBranch();
+ }
+
+ /** @test */
+ public function error_invalid_data_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'purchase_invoice_id', null);
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "The given data was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_purchase_invoice_done_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $purchaseInvoice = PurchaseReturn::findOrFail($data->purchase_invoice_id);
+ $purchaseInvoice->form->done = 1;
+ $purchaseInvoice->form->save();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Invoice already done!"
+ ]);
+ }
+
+ /** @test */
+ public function error_note_more_than_255_character_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'notes', $this->faker->text(300));
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Notes can\t more than 255 character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_note_contain_space_on_first_or_last_character_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'notes', ' notes ');
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Notes can\t contain space on first or last character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_overquantity_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'items.0.quantity', 300);
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Purchase return item qty can't exceed purchase invoice qty"
+ ]);
+ }
+
+ /** @test */
+ public function error_invalid_total_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'amount', 180000);
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Amount was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_journal_not_set_create_purchase_return()
+ {
+ $this->setRole();
+
+ $data = $this->getDummyData();
+ SettingJournal::where('feature', 'purchase')->where('name', 'account payable')->delete();
+
+ $response = $this->json('POST', self::$path, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Journal purchase account - account payable not found"
+ ]);
+
+ $this->generateChartOfAccount();
+ }
+
+ /** @test */
+ public function success_read_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('GET', self::$path.'/'.$purchaseReturn->id, [
+ 'includes' => 'items.item;items.allocation;;form.createdBy;form.requestApprovalTo;form.branch'
+ ], $this->headers);
+
+ $response->assertStatus(200)
+ ->assertJson([
+ "data" => [
+ "id" => $purchaseReturn->id,
+ "form" => [
+ "id" => $purchaseReturn->form->id,
+ "date" => $purchaseReturn->form->date,
+ "number" => $purchaseReturn->form->number,
+ "notes" => $purchaseReturn->form->notes,
+ ]
+ ]
+ ]);
+ }
+
+ /** @test */
+ public function unauthorized_read_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('GET', self::$path.'/'.$purchaseReturn->id, [
+ 'includes' => 'items.item;items.allocation;;form.createdBy;form.requestApprovalTo;form.branch'
+ ], $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `read purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_read_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetBranch();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $response = $this->json('GET', self::$path.'/'.$purchaseReturn->id, [
+ 'includes' => 'items.item;items.allocation;;form.createdBy;form.requestApprovalTo;form.branch'
+ ], $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to read this form"
+ ]);
+ $this->setBranch();
+ }
+
+ /** @test */
+ public function success_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData($purchaseReturn);
+ $data = data_set($data, 'items.0.quantity', 10);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(201);
+ $this->assertDatabaseHas('forms', [ 'edited_number' => $response->json('data.form.number') ], 'tenant');
+ $this->assertDatabaseHas('user_activities', [
+ 'number' => $response->json('data.form.number'),
+ 'table_id' => $response->json('data.id'),
+ 'table_type' => 'PurchaseReturn',
+ 'activity' => 'Update - 1'
+ ], 'tenant');
+
+ $this->assertDatabaseHas('forms', [
+ 'id' => $response->json('data.form.id'),
+ 'number' => $response->json('data.form.number'),
+ 'approval_status' => 0,
+ 'done' => 0,
+ ], 'tenant');
+
+ $this->assertDatabaseHas('purchase_returns', [
+ 'id' => $response->json('data.id'),
+ 'supplier_name' => $response->json('data.supplier_name'),
+ 'purchase_invoice_id' => $data->purchase_invoice_id,
+ ], 'tenant');
+
+ $this->assertDatabaseHas('purchase_return_items', [
+ 'purchase_return_id' => $response->json('data.id'),
+ 'item_id' => $data->items[0]->item_id,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function error_invalid_data_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'purchase_invoice_id', null);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "The given data was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_form_already_done_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturn->form->done = 1;
+ $purchaseReturn->form->save();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'purchase_invoice_id', null);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Can't update, form already done!"
+ ]);
+ }
+
+ /** @test */
+ public function error_note_more_than_255_character_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'notes', $this->faker->text(300));
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Notes can\t more than 255 character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_note_contain_space_on_first_or_last_character_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'notes', ' notes ');
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Notes can\t contain space on first or last character!"
+ ]);
+ }
+
+ /** @test */
+ public function error_overquantity_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'items.0.quantity', 300);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Purchase return item qty can't exceed purchase invoice qty"
+ ]);
+ }
+
+ /** @test */
+ public function error_invalid_total_amount_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ $data = data_set($data, 'amount', 18000);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Amount was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function error_journal_not_set_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData();
+ SettingJournal::where('feature', 'purchase')->where('name', 'account payable')->delete();
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Journal purchase account - account payable not found"
+ ]);
+
+ $this->generateChartOfAccount();
+ }
+
+ /** @test */
+ public function unauthorized_edit_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData($purchaseReturn);
+ $data = data_set($data, 'items.0.quantity', 10);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `update purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_update_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetBranch();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+
+ $data = $this->getDummyData($purchaseReturn);
+ $data = data_set($data, 'items.0.quantity', 10);
+
+ $response = $this->json('PATCH', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to update this form"
+ ]);
+ $this->setBranch();
+ }
+
+ /** @test */
+ public function success_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(204);
+ $this->assertDatabaseHas('forms', [
+ 'number' => $purchaseReturn->form->number,
+ 'request_cancellation_reason' => $data['reason'],
+ 'cancellation_status' => 0,
+ ], 'tenant');
+ }
+
+ /** @test */
+ public function error_form_already_done_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturn->form->done = 1;
+ $purchaseReturn->form->save();
+
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "Can't delete, form already done!"
+ ]);
+ }
+
+ /** @test */
+ public function error_no_reason_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $purchaseReturn->form->done = 1;
+ $purchaseReturn->form->save();
+
+ $data['reason'] = null;
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "The given data was invalid."
+ ]);
+ }
+
+ /** @test */
+ public function unauthorized_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetUserRole();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(500)
+ ->assertJson([
+ "code" => 0,
+ "message" => "There is no permission named `delete purchase return` for guard `api`."
+ ]);
+ }
+
+ /** @test */
+ public function error_default_branch_delete_purchase_return()
+ {
+ $this->success_create_purchase_return();
+ $this->unsetBranch();
+
+ $purchaseReturn = PurchaseReturn::orderBy('id', 'asc')->first();
+ $data['reason'] = $this->faker->text(200);
+
+ $response = $this->json('DELETE', self::$path . '/' . $purchaseReturn->id, $data, $this->headers);
+
+ $response->assertStatus(422)
+ ->assertJson([
+ "code" => 422,
+ "message" => "please set default branch to delete this form"
+ ]);
+ $this->setBranch();
+ }
+
+}
\ No newline at end of file