diff --git a/app/Classes/General/Helper.php b/app/Classes/General/Helper.php index 8b5061ec..074eb26e 100644 --- a/app/Classes/General/Helper.php +++ b/app/Classes/General/Helper.php @@ -84,7 +84,7 @@ class Helper $ringgitWords = $numberTransformer->toWords((int)$ringgit); $centsWords = $numberTransformer->toWords((int)$cents); - return strtoupper('ringgit ' . $ringgitWords . ' and ' . $centsWords . ' cents only'); + return strtoupper('ringgit malaysia ' . $ringgitWords . ' and ' . $centsWords . ' cents only'); } public static function getLHDNStateCodeByName($name) diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBankingInvoiceTransactionLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBankingInvoiceTransactionLogic.php new file mode 100644 index 00000000..884614fe --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBankingInvoiceTransactionLogic.php @@ -0,0 +1,71 @@ + 'Create Banking Invoice Transaction', + 'message' => 'You have successfully create banking invoice transaction' + ]; + } + + /** @var CanFetchBooking */ + private $canFetchBooking; + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var CreateBankingInvoiceTransactionProcessor */ + private $createBankingInvoiceTransactionProcessor; + + /** + * CreateBankingInvoiceTransactionLogic constructor. + * @param CanFetchBooking $canFetchBooking + * @param FetchesBooking $fetchesBooking + * @param CreateBankingInvoiceTransactionProcessor $createBankingInvoiceTransactionProcessor + */ + public function __construct( + CanFetchBooking $canFetchBooking, + FetchesBooking $fetchesBooking, + CreateBankingInvoiceTransactionProcessor $createBankingInvoiceTransactionProcessor + ) + { + $this->canFetchBooking = $canFetchBooking; + $this->fetchesBooking = $fetchesBooking; + $this->createBankingInvoiceTransactionProcessor = $createBankingInvoiceTransactionProcessor; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + // $this->canFetchBooking->passes(); + + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $this->createBankingInvoiceTransactionProcessor->execute($booking); + + return $this->resourceResponse(new BookingResource($booking)); + } + +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateBankingInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateBankingInvoiceTransactionProcessor.php new file mode 100644 index 00000000..eb3c3819 --- /dev/null +++ b/app/Classes/Modules/Transactions/Processors/CreateBankingInvoiceTransactionProcessor.php @@ -0,0 +1,233 @@ +createsTransaction = $createsTransaction; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->fetchesCompany = $fetchesCompany; + $this->createsDocument = $createsDocument; + $this->createsFile = $createsFile; + $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->fetchesBookingQuotation = $fetchesBookingQuotation; + $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; + } + + + /** + * @param Booking $booking + * @return void + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(Booking $booking) + { + $po_order_transaction = $booking->transactions() + ->where('type', TransactionType::PURCHASE_ORDER) + ->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED]) + ->first(); + + $transaction = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->whereNotIn('status', [ApprovalStatus::SUSPENDED]) + ->first(); + + if (!$transaction) { + $outstanding = $this->calculatesBookingOutstanding->execute($booking); + + $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $outstanding)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0 : 1, PaymentMethodType::CASH); + + $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject); //cief todo: 76 + + $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); + + $billNumber = $this->generatesTransactionBillNumber->execute('PYMT-'); + + $object = new TransactionObject( + $billNumber, + TransactionType::PAYMENT, + 1, + $booking->company->id, + $configurations->getConfigurations()->getBankId(), + $configurations->getConversionObject()->getPaymentMethod(), + $configurations->getTotal(), + $configurations->getForeignTotal(), + 1, + $configurations->getConversionObject()->getCurrencyId(), + $configurations->getConfigurations()->getRate(), + $configurations->getTax(), + $configurations->getServiceCharge(), + Carbon::now()->addMinutes($paymentAttemptLimit), + ApprovalStatus::PENDING_SUBMISSION, + [], + isset($billPlzBill) ? $billPlzBill->id : NULL + ); + + $this->createsTransaction->execute($booking, $object); + } + + $billNumber = $this->generatesTransactionBillNumber->execute('BI-'); + + $payable_amount = $booking->transactions()->payments()->where(function ($query) { + return $query->where(function ($query) { + // return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString()); + return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->where('expires_on', '>=', Carbon::now()); + })->orWhere(function ($query) { + return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }); + })->sum('amount'); + $booking_amount = $booking->fix_amount; + + $transaction = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->first(); + + $paymentAmount = $booking->transactions()->payments()->where(function ($query) { + return $query->where(function ($query) { + return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->where('expires_on', '>=', Carbon::now()); + })->orWhere(function ($query) { + return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }); + })->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total'); + + $booking_currency_average_rate = $booking_amount / $paymentAmount; + + $total_service_charge = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED]) + ->sum('service_charge'); + + $total_tax = $booking->transactions() + ->where('type', TransactionType::PAYMENT) + ->whereIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED]) + ->sum('tax'); + + // delete prev banking transactions + $booking->transactions() + ->where('type', TransactionType::BANKING) + ->delete(); + + $transaction_object = new TransactionObject( + $billNumber, + TransactionType::BANKING, + $transaction->issuer, + $transaction->receiver, + $transaction->recipient_bank_account_id, + $transaction->payment_method, + $payable_amount, + $booking_amount, + $transaction->currency_id, + $transaction->original_currency_id, + $booking_currency_average_rate, + $total_tax, + $total_service_charge, + null, + ApprovalStatus::APPROVED + ); + + $banking_transaction = $this->createsTransaction->execute($po_order_transaction->booking, $transaction_object); + + $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); + $brn = $supplier->documents()->where('document_type', DocumentType::SSM_REGISTRATION)->latest()->first(); + + // PDF 1 - Banking Invoice + $purchase_order_pdf = LaravelMpdf::loadView('pages.pdfs.banking_invoice', + [ + 'transaction' => $banking_transaction, + 'po_order_transaction' => $po_order_transaction, + 'supplier' => $supplier, + 'brn' => $brn, + ]); + $document_object = new DocumentObject( + DocumentType::BANKING_INVOICE, + [chunk_split('data:application/pdf;base64,' . base64_encode($purchase_order_pdf->output()))], + '', + ApprovalStatus::COMPLETED, + 'banking_invoices' + ); + + /** @var Document $document */ + $document = $this->createsDocument->execute($po_order_transaction->booking, $document_object); + $this->createsFile->execute($document, $document_object); + + // PDF 2 - Banking Delivery Order + $purchase_order_pdf = LaravelMpdf::loadView('pages.pdfs.deliver_order_banking', + [ + 'transaction' => $banking_transaction, + 'po_order_transaction' => $po_order_transaction, + 'supplier' => $supplier, + 'brn' => $brn, + ]); + $document_object = new DocumentObject( + DocumentType::DELIVER_ORDER_BANKING, + [chunk_split('data:application/pdf;base64,' . base64_encode($purchase_order_pdf->output()))], + '', + ApprovalStatus::COMPLETED, + 'banking_invoices' + ); + + /** @var Document $document */ + $document = $this->createsDocument->execute($po_order_transaction->booking, $document_object); + $this->createsFile->execute($document, $document_object); + } +} diff --git a/app/Classes/ValueObjects/Constants/DocumentType.php b/app/Classes/ValueObjects/Constants/DocumentType.php index 91ff84bb..8da383d4 100644 --- a/app/Classes/ValueObjects/Constants/DocumentType.php +++ b/app/Classes/ValueObjects/Constants/DocumentType.php @@ -30,4 +30,7 @@ final class DocumentType { public const RECEIPT_VOUCHER = 'RECEIPT_VOUCHER'; public const EINVOICE = 'E_INVOICE'; + + public const BANKING_INVOICE = 'BANKING_INVOICE'; + public const DELIVER_ORDER_BANKING = 'DELIVER_ORDER_BANKING'; } diff --git a/app/Classes/ValueObjects/Constants/TransactionType.php b/app/Classes/ValueObjects/Constants/TransactionType.php index ee1d86b0..6f67adc5 100644 --- a/app/Classes/ValueObjects/Constants/TransactionType.php +++ b/app/Classes/ValueObjects/Constants/TransactionType.php @@ -40,6 +40,8 @@ final class TransactionType { public const RECEIPT_VOUCHER = 17; + public const BANKING = 18; + public const ID_TO_NAME = [ self::PAYMENT_ATTEMPT => "PAYMENT_ATTEMPT", self::PAYMENT => "PAYMENT", @@ -59,6 +61,7 @@ final class TransactionType { self::SUPPLIER_REFUND => "SUPPLIER_REFUND", self::BILL_REFUND => "BILL_REFUND", self::RECEIPT_VOUCHER => "RECEIPT_VOUCHER", + self::BANKING => "BANKING", ]; - } +} diff --git a/app/Http/Controllers/Bookings/CreateBankingInvoiceTransactionController.php b/app/Http/Controllers/Bookings/CreateBankingInvoiceTransactionController.php new file mode 100644 index 00000000..dc1636aa --- /dev/null +++ b/app/Http/Controllers/Bookings/CreateBankingInvoiceTransactionController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 9c6edf96..fef78809 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -65,6 +65,8 @@ class BookingResource extends JsonResource 'supplier_delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()), 'proforma_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()), 'ecommerce_purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->first()), + 'banking_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::BANKING_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()), + 'delivery_order_banking' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER_BANKING)->orderByDesc('id')->first()), ], 'order_reference_no' => $this->modelAttributes()->where('name', BookingAttributeNames::ORDER_REFERENCE_NO)->get()->map(function ($attr) { return [ diff --git a/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue b/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue index 36432a62..1334615c 100644 --- a/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue @@ -72,7 +72,7 @@
The recipient can expect to receive the transfer within 3-5 working days. Explore our BANK TRANSFER (SAVER) option for a better rate!
Enjoy a better rate with this option! The recipient will receive the transfer after 5-7 working days.
You can request Pay-on-Behalf via Alipay for platforms like Taobao, 1688, Pinduoduo, or any Alipay-supported platform.
Please use Alipay account "2766384544@QQ.com" to apply for Daifu. This account may change, so always confirm the latest Alipay account before placing an order.
The customer may request an official invoice first for Bank submission (e.g. BA Trade Line).
+ The 2% service fee is already included in each product unit price, so it will not appear separately.
+ 🕓 Transfer will be processed once bank payment is received.
+
The customer may request an official invoice first for Bank submission (e.g. BA Trade Line).
+ Invoice will show a 2% service fee as a separate item.
+ 🕓 Transfer will be processed once bank payment is received.
+
Please ensure is a PERSONAL bank account details. Company bank account details only allow to use as E2E service.
Cancellation of E2E service are strictly NO refund on the 2% transfer fee charge.
Proforma Invoice
-Banking Invoice
+Banking Delivery Order
+Proforma Invoice
+Amount: {{$booking->fix_amount.' '.$booking->fixedCurrency->short_code}}
Status: {{$booking->status === 3 ? 'Complete' : 'In Progress'}}
Purchase Order Status: {{$purchaseOrder ? ($purchaseOrder->status === 3 ? 'Approved' : ($purchaseOrder->status === 1 ? 'Pending Approval' : 'Incomplete Submission')) : 'Pending Submission'}}
+Marking: {{$booking->company->reference}}
+ @if($payments)Payment History:
@endif @php $i = 1; @endphp @foreach($payments as $payment) @@ -123,10 +131,12 @@ $purchaseOrder = $booking->transactions()->where('type', \App\Classes\ValueObjects\Constants\TransactionType::PURCHASE_ORDER)->first(); @endphpAmount: {{$booking->fix_amount.' '.$booking->fixedCurrency->short_code}}
Status: {{$booking->status === 3 ? 'Complete' : 'In Progress'}}
Purchase Order Status: {{$purchaseOrder ? ($purchaseOrder->status === 3 ? 'Approved' : ($purchaseOrder->status === 1 ? 'Pending Approval' : 'Incomplete Submission')) : 'Pending Submission'}}
+Marking: {{$booking->company->reference}}
+ @if($payments)Payment History:
@endif @php $i = 1; @endphp @foreach($payments as $payment) diff --git a/resources/views/pages/pdfs/banking_invoice.blade.php b/resources/views/pages/pdfs/banking_invoice.blade.php new file mode 100644 index 00000000..2e371273 --- /dev/null +++ b/resources/views/pages/pdfs/banking_invoice.blade.php @@ -0,0 +1,97 @@ +@extends('layouts.base_pdf') + +@section('inner_content') + +
+
+ |
+
+ CIEF WORLDWIDE SDN BHD
+ (1134596-M) + No. 72-3, Jalan Jalil 1, + The Earth Bukit Jalil, + 57000 Kuala Lumpur + Tel: 03-8082 1252 + TIN: C23880226040, MSIC: 46909 + SST: W10-2403-32000643 + |
+
+ Invoice
+ EBI#: {{ $transaction->bill_no }}
+ Ref# {{ $transaction->booking->marking }}
+ Date: {{ $po_order_transaction->booking->created_at }}
+ Terms: C.O.D
+ |
+
| + Bill To + | +||
|
+
+ {{ $supplier->name }}
+ @if ($brn)
+ (ROC: {{ $brn->reference }})
+ @endif
+
+
+ @php
+ $billingAddress = $supplier->addresses()->where('billing', '=', true)->first();
+ @endphp
+ {{ $billingAddress->street_one }}
+ {{ $billingAddress->street_two }},
+ {{ $billingAddress->district()->first()->name }},
+ {{ $billingAddress->postcode }}
+ {{ $billingAddress->state()->first()->name }},
+ {{ $billingAddress->country()->first()->name }}
+
+ Phone: {{ $supplier->contacts()->first()->phone }}
+ |
+ ||
{{ \App\Classes\General\Helper::convert(round($transaction->amount, 2)) }}
+ Notes:| This is generated by computer. No signature required. | +Page {PAGENO} of {nbpg} | +
+
+ |
+
+ CIEF WORLDWIDE SDN BHD
+ (1134596-M) + No. 72-3, Jalan Jalil 1, + The Earth Bukit Jalil, + 57000 Kuala Lumpur + Tel: 03-8082 1252 + TIN: C23880226040, MSIC: 46909 + SST: W10-2403-32000643 + |
+
+
+
+ Delivery Order
+
+
+
+ EBDO#: {{ str_replace(['BI-'], 'BDO-', $transaction->bill_no) }}
+ Ref#: {{ $transaction->booking->marking }}
+ Date: {{
+ $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $po_order_transaction->created_at }}
+ |
+
| + + Bill To + + | +||
|
+
+ {{ $supplier->name }}
+ @if ($brn)
+ (ROC: {{ $brn->reference }})
+ @endif
+
+
+ @php
+ $billingAddress = $supplier->addresses()->where('billing', '=', true)->first();
+ @endphp
+ {{ $billingAddress->street_one }}
+ {{ $billingAddress->street_two }} ,
+ {{ $billingAddress->district()->first()->name }},
+ {{ $billingAddress->postcode }}
+ {{ $billingAddress->state()->first()->name }},
+ {{ $billingAddress->country()->first()->name }}
+
+
+ Phone: {{ $supplier->contacts()->first()->phone }}
+
+ |
+ ||
| + + | +
+ E & O.E + Receive In Good Order & Condition + |
+
|
+ CIEF WORLDWIDE SDN BHD + |
+ + + | +
| This is generated by computer. No signature required. | +Page {PAGENO} of {nbpg} | +