Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
205dd90
[Payment] Cancellation approval
leeellaaa-kuy Oct 26, 2022
7a0be28
[Payment] Integrate cash out with cash advance
leeellaaa-kuy Oct 27, 2022
4939b8a
[Payment] Preparing CashOutTest
leeellaaa-kuy Oct 27, 2022
88b7270
[Payment] Get references for payment
leeellaaa-kuy Oct 29, 2022
29c8b0b
[Payment] Get paymentables for payment
leeellaaa-kuy Oct 30, 2022
b5d8e5c
[Payment] Split request filter for getReferences & make paginate_coll…
leeellaaa-kuy Oct 31, 2022
cd95e31
[Payment] Fix request filter on getReferences
leeellaaa-kuy Oct 31, 2022
1068118
[Payment] Transform return data on getReferences & make getPaymentabl…
leeellaaa-kuy Nov 1, 2022
1a6a960
[Payment] Fix payment routing
leeellaaa-kuy Nov 1, 2022
404baed
[Payment] Revert transform data on getReferences
leeellaaa-kuy Nov 1, 2022
c6e5acb
[Payment] Revert transform data on getReferences
leeellaaa-kuy Nov 1, 2022
d40c5d5
[Payment] Add paymentable_id on getPaymentables
leeellaaa-kuy Nov 2, 2022
2520be5
[Payment] WIP request cancellation
leeellaaa-kuy Nov 3, 2022
ead9611
[Payment] Save allocation reports
leeellaaa-kuy Nov 3, 2022
cde3583
[Payment] Fix sort by on getReferences
leeellaaa-kuy Nov 3, 2022
a14d2df
WIP fix payment with cash advance
leeellaaa-kuy Nov 6, 2022
e6028c0
Fix typo attribute
leeellaaa-kuy Nov 6, 2022
42486c1
[Payment] Feature test create cash out
leeellaaa-kuy Nov 7, 2022
6dffa04
[Payment] Feature test for create cash out
leeellaaa-kuy Nov 7, 2022
4cb8a84
Merge branch 'fix-cash-advance' into development
leeellaaa-kuy Nov 7, 2022
184c301
[Payment] Add validation on cash/bank out & fix delete cash out
leeellaaa-kuy Nov 8, 2022
9cd8e39
[Payment] Fix mail format on cancellation request
leeellaaa-kuy Nov 8, 2022
1caa45f
Enable user to request delete although has been rejected
leeellaaa-kuy Nov 9, 2022
f06b0d1
Fix rejected cancellation approval by email
leeellaaa-kuy Nov 9, 2022
3c20115
Fix validation & remove unused codes
leeellaaa-kuy Nov 10, 2022
6e0772b
Tdd cash out cancellation
leeellaaa-kuy Nov 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

namespace App\Http\Controllers\Api\Finance\Payment;

use App\Exceptions\ApprovalNotFoundException;
use App\Exceptions\PointException;
use App\Exceptions\UnauthorizedException;
use App\Http\Controllers\Controller;
use App\Http\Resources\ApiResource;
use App\Model\Accounting\Journal;
use App\Model\Finance\CashAdvance\CashAdvance;
use App\Model\Finance\Payment\Payment;
use App\Model\UserActivity;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class PaymentCancellationApprovalController extends Controller
{
/**
* @param Request $request
* @param $id
* @return ApiResource
* @throws UnauthorizedException
* @throws ApprovalNotFoundException
*/
public function approve(Request $request, $id)
{
$payment = Payment::findOrFail($id);

// ### Approve fail if
$this->isCancellationRequestStillValid($payment);
if ($request->has('token')) {
// approve from email
$approvalBy = $request->get('approver_id');
} else {
// Jika Role Bukan Super Admin dan tidak memiliki akses approval maka mengirimkan pesan eror
$payment->isHaveAccessToDelete();
$approvalBy = auth()->user()->id;
}

DB::connection('tenant')->transaction(function () use ($payment, $approvalBy) {
// ### If approve success then
// Status form cash out akan menjadi cancelled
$payment->form->cancellation_approval_by = $approvalBy;
$payment->form->cancellation_approval_at = now();
$payment->form->cancellation_status = 1;
$payment->form->save();

// Jumlah saldo cash account / cash advance/ biaya yang dipilih akan bertambah sebesar data yang dihapus
// Pengembalian dana cash advance & status formnya menjadi pending
$amountPaidByCashAdvance = 0;
if ($payment->cashAdvance) {
$cashAdvancePayment = $payment->cashAdvance;
$cashAdvance = $cashAdvancePayment->cashAdvance;
$amountPaidByCashAdvance = $payment->cashAdvance->amount;

$cashAdvance->amount_remaining += $amountPaidByCashAdvance;
$cashAdvance->save();

$cashAdvance->form->done = 0;
$cashAdvance->form->save();

$activity = 'Payment Refund (' . $payment->form->number . ')';
$this->writeHistory($cashAdvance, $approvalBy, $activity);
}

// Pengembalian dana account
$amountPaidByAccount = $payment->amount - $amountPaidByCashAdvance;
$journal = new Journal;
$journal->form_id = $payment->form->id;
$journal->journalable_type = $payment->paymentable_type;
$journal->journalable_id = $payment->paymentable_id;
$journal->chart_of_account_id = $payment->payment_account_id;
if ($payment->disbursed) {
$journal->debit = $amountPaidByAccount;
} else {
$journal->credit = $amountPaidByAccount;
}
$journal->save();

foreach ($payment->details as $paymentDetail) {
$journal = new Journal;
$journal->form_id = $payment->form->id;
$journal->form_id_reference = optional(optional($paymentDetail->referenceable)->form)->id;
$journal->journalable_type = $payment->paymentable_type;
$journal->journalable_id = $payment->paymentable_id;
$journal->notes = $paymentDetail->notes;
$journal->chart_of_account_id = $paymentDetail->chart_of_account_id;
if (!$payment->disbursed) {
$journal->credit = $paymentDetail->amount;
} else {
$journal->debit = $paymentDetail->amount;
}
$journal->save();

// Status form reference jadi pending
$paymentDetail->referenceable->form->done = 0;
$paymentDetail->referenceable->form->save();
}

// Delete data allocation pada allocation report
$payment->allocationReports()->delete();
});

$payment->load('form');
return new ApiResource($payment);
}

/**
* @param Request $request
* @param $id
* @return ApiResource
* @throws ApprovalNotFoundException
* @throws UnauthorizedException
*/
public function reject(Request $request, $id)
{
$payment = Payment::findOrFail($id);

// ### Reject fail if
$this->isCancellationRequestStillValid($payment);
if ($request->has('token')) {
// reject from email
$approvalBy = $request->get('approver_id');
$request->merge(['reason' => 'Rejected by email']);
} else {
$request->validate([
'reason' => 'required'
]);
// Jika Role Bukan Super Admin / Pihak yang dipilih utk approval maka akan mengirimkan pesan eror
// Jika tidak memiliki akses approval pada payment order maka akan mengirimkan pesan eror
$payment->isHaveAccessToDelete();
$approvalBy = auth()->user()->id;
}

DB::connection('tenant')->transaction(function () use ($payment, $request, $approvalBy) {
// ### If reject success then
// Update status approval form menjadi rejected
$payment->form->approval_status = -1;

// Update status form status menjadi pending
$payment->form->done = 0;

$payment->form->cancellation_approval_by = $approvalBy;
$payment->form->cancellation_approval_at = now();
$payment->form->cancellation_approval_reason = $request->get('reason');
$payment->form->cancellation_status = -1;

$payment->form->save();
});

$payment->form = $payment->form;
return new ApiResource($payment);
}

public function isCancellationRequestStillValid($payment)
{
// is cancellation request already approved?
$cancellationStatus = $payment->form->cancellation_status;
if ($cancellationStatus == 1) {
throw new PointException('Form cancellation already approved');
}
// is cancellation request already rejected?
// if ($cancellationStatus == -1) {
// throw new PointException('Form cancellation already rejected');
// }
}

// $reference = cash advance,
public function writeHistory($reference, int $userId, string $activity)
{
$history = new UserActivity;

$history->table_type = $reference::$morphName;
$history->table_id = $reference->id;
$history->number = $reference->form->number;
$history->user_id = $userId;
$history->date = convert_to_local_timezone(date('Y-m-d H:i:s'));
$history->activity = $activity;

$history->save();
}
}
138 changes: 124 additions & 14 deletions app/Http/Controllers/Api/Finance/Payment/PaymentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@
use App\Http\Requests\Finance\Payment\Payment\UpdatePaymentRequest;
use App\Http\Resources\ApiCollection;
use App\Http\Resources\ApiResource;
use App\Mail\Finance\Payment\PaymentCancellationApprovalRequest;
use App\Model\Auth\Role;
use App\Model\Finance\Payment\Payment;
use App\Model\Finance\PaymentOrder\PaymentOrder;
use App\Model\Master\User;
use App\Model\Purchase\PurchaseDownPayment\PurchaseDownPayment;
use App\Model\Token;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Throwable;

class PaymentController extends Controller
Expand All @@ -23,7 +32,7 @@ class PaymentController extends Controller
*/
public function index(Request $request)
{
$payment = Payment::from(Payment::getTableName().' as '.Payment::$alias)->eloquentFilter($request);
$payment = Payment::from(Payment::getTableName() . ' as ' . Payment::$alias)->eloquentFilter($request);

$payment = Payment::joins($payment, $request->get('join'));

Expand All @@ -47,7 +56,8 @@ public function store(StorePaymentRequest $request)
->load('form')
->load('paymentable')
->load('details.allocation')
->load('details.referenceable.form');
->load('details.referenceable.form')
->load('cashAdvance.cashAdvance.form');

return new ApiResource($payment);
});
Expand Down Expand Up @@ -83,7 +93,7 @@ public function update(UpdatePaymentRequest $request, $id)
$payment->form->archive();

foreach ($payment->details as $paymentDetail) {
if (! $paymentDetail->isDownPayment()) {
if (!$paymentDetail->isDownPayment()) {
$reference = $paymentDetail->referenceable;
$reference->remaining += $paymentDetail->amount;
$reference->save();
Expand Down Expand Up @@ -114,23 +124,123 @@ public function update(UpdatePaymentRequest $request, $id)
*/
public function destroy(Request $request, $id)
{
$request->validate([
'reason' => 'required'
]);

$payment = Payment::findOrFail($id);
$payment->isAllowedToDelete();

$response = $payment->requestCancel($request);

if (! $response) {
foreach ($payment->details as $paymentDetail) {
if (! $paymentDetail->isDownPayment()) {
$reference = $paymentDetail->referenceable;
$reference->remaining += $payment->amount;
$reference->save();
$reference->form->done = false;
$reference->form->save();
DB::connection('tenant')->transaction(function () use ($payment, $request) {
$payment->requestCancel($request);

// Kirim notifikasi by program & email
$superAdminRole = Role::where('name', 'super admin')->first();
$emailUsers = User::whereHas('roles', function (Builder $query) use ($superAdminRole) {
$query->where('role_id', '=', $superAdminRole->id);
})->get();

foreach ($emailUsers as $recipient) {
// create token based on request_approval_to
$token = Token::where('user_id', $recipient->id)->first();

if (!$token) {
$token = new Token([
'user_id' => $recipient->id,
'token' => md5($recipient->email . '' . now()),
]);
$token->save();
}

Mail::to([
$recipient->email,
])->queue(new PaymentCancellationApprovalRequest(
$payment,
$recipient,
$payment->form,
$token->token
));
}
}

// if (!$response) {
// foreach ($payment->details as $paymentDetail) {
// if (!$paymentDetail->isDownPayment()) {
// $reference = $paymentDetail->referenceable;
// $reference->remaining += $payment->amount;
// $reference->save();
// $reference->form->done = false;
// $reference->form->save();
// }
// }
// }
});

return response()->json([], 204);
}

public function getReferences(Request $request)
{
// Split request filter for each reference type
$paymentOrderRequest = new Request();
$downPaymentRequest = new Request();
$paymentOrderString = 'paymentorder';
$downPaymentString = 'downpayment';
foreach ($request->all() as $key => $value) {
if (in_array($key, ['limit', 'page'])) {
$paymentOrderRequest->merge([
$key => $value
]);
$downPaymentRequest->merge([
$key => $value
]);
continue;
}
$explodedKey = explode('_', $key);

switch ($explodedKey[0]) {
case $paymentOrderString:
$keyAttribute = substr($key, strlen($paymentOrderString) + 1); //+1 for _
$paymentOrderRequest->merge([
$keyAttribute => $value
]);
break;

case $downPaymentString:
$keyAttribute = substr($key, strlen($downPaymentString) + 1); //+1 for _
$downPaymentRequest->merge([
$keyAttribute => $value
]);
break;

default:
# code...
break;
}
}

$references = new Collection();

$paymentOrders = PaymentOrder::from(PaymentOrder::getTableName() . ' as ' . PaymentOrder::$alias)->eloquentFilter($paymentOrderRequest);
$paymentOrders = PaymentOrder::joins($paymentOrders, $paymentOrderRequest->get('join'))->get();
$references = $references->concat($paymentOrders);

$downPayments = PurchaseDownPayment::from(PurchaseDownPayment::getTableName() . ' as ' . PurchaseDownPayment::$alias)->eloquentFilter($downPaymentRequest);
$downPayments = PurchaseDownPayment::joins($downPayments, $downPaymentRequest->get('join'))->get();
$references = $references->concat($downPayments);

$references = $references->sortBy($request->get('sort_by'));
$paginatedReferences = paginate_collection($references, $request->get('limit'), $request->get('page'));

return new ApiCollection($paginatedReferences);
}

public function getPaymentables(Request $request)
{
$paymentables = Payment::from(Payment::getTableName() . ' as ' . Payment::$alias)
->select(['paymentable_id', 'paymentable_type', 'paymentable_name'])
->eloquentFilter($request);
$paymentables = pagination($paymentables, $request->get('limit'));

return new ApiCollection($paymentables);
}
}
Loading