E-Invoice - Partial completion of => Doc Delivery - E-INVOICE, E-CN, E-RN

This commit is contained in:
Dillon Ngo
2025-06-06 03:17:52 +08:00
parent 094e60e9c3
commit 893631064b
29 changed files with 1036 additions and 72 deletions
@@ -93,9 +93,10 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$invoice = $booking->transactions()->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first();
if(auth()->user()->type === 3) {
throw new MalformedRequestException('You do not have the permission to refund the order.');
}
//cief todo: 90 - move this into rules
// if(auth()->user()->type === 3) {
// throw new MalformedRequestException('You do not have the permission to refund the order.');
// }
$billNumber = $this->generatesTransactionBillNumber->execute('RFD-');
@@ -113,7 +114,7 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$refundAmount = $transaction->original_amount / $transaction->currency_rate;
$service_charges_to_refund = $transaction->service_charge;
} else {
// partial refund
// partial refund
$refundAmount = bcdiv($request->input('amount'), $transaction->currency_rate, 7);
$bookingAmountBeforeCurrentRefund = $booking->fix_amount - $refundInPending;
@@ -157,7 +158,7 @@ class CreateBookingRefundLogic extends AbstractControllerLogic
$refund_transaction = $this->createsTransaction->execute($transaction, $object);
$bookingInWhiteForm = $transaction->transactions()->bills()->first();
$bookingInWhiteForm = $transaction->transactions()->bills()->first(); // if no white form created yet can approve right away
// create supplier refund
if ($bookingInWhiteForm) {
@@ -9,7 +9,6 @@ use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Documents\Services\DeletesDocument;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionWithInvoiceNoProcessor;
use Illuminate\Support\Str;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Http\Resources\BookingResource;
@@ -52,9 +51,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
/** @var CreateInvoiceTransactionProcessor */
private $createInvoiceTransactionProcessor;
/** @var CreateInvoiceTransactionWithInvoiceNoProcessor */
private $createInvoiceTransactionWithInvoiceNoProcessor;
/**
* FetchBookingLogic constructor.
* @param CanFetchBooking $canFetchBooking
@@ -63,7 +59,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
* @param UpdatesBookingStatus $updatesBookingStatus
* @param DeletesDocument $deletesDocument
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
* @param CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor
*/
public function __construct(
CanFetchBooking $canFetchBooking,
@@ -71,8 +66,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
DeletesTransaction $deletesTransaction,
UpdatesBookingStatus $updatesBookingStatus,
DeletesDocument $deletesDocument,
CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor,
CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor
CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
) {
$this->canFetchBooking = $canFetchBooking;
$this->fetchesBooking = $fetchesBooking;
@@ -80,7 +74,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
$this->updatesBookingStatus = $updatesBookingStatus;
$this->deletesDocument = $deletesDocument;
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
$this->createInvoiceTransactionWithInvoiceNoProcessor = $createInvoiceTransactionWithInvoiceNoProcessor;
}
@@ -119,8 +112,10 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
// update currentInvoice bill_no to '-deleted-'
$currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first();
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp);
$currentInvoice->save();
if($currentInvoice){
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp);
$currentInvoice->save();
}
$transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get();
if ($transactionWithSameBillNo) {
@@ -140,7 +135,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic
$this->deletesDocument->execute($row);
}
$this->createInvoiceTransactionWithInvoiceNoProcessor->execute($booking, $firstBillNo);
$this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo);
return $this->resourceResponse(new BookingResource($booking));
}
@@ -13,6 +13,10 @@ use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\General\AWSS3Helper;
use Illuminate\Support\Facades\Storage;
/**
* @deprecated This class is deprecated and should not be used.
* Use `GenerateCreditNotePdfV2Logic` instead
*/
class GenerateCreditNotePdfLogic
{
@@ -0,0 +1,115 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use Illuminate\Http\Request;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\General\AWSS3Helper;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\KeyValuePair;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class GenerateCreditNotePdfV2Logic
{
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var FetchesCompany */
private $fetchesCompany;
/**
* GenerateCreditNotePdfV2Logic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param FetchesCompany $fetchesCompany
*/
public function __construct(FetchesTransaction $fetchesTransaction, FetchesCompany $fetchesCompany)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->fetchesCompany = $fetchesCompany;
}
/**
* @param Request $request
* @return string|\Symfony\Component\HttpFoundation\Response
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Request $request)
{
$pdfTemplateName = 'pages.pdfs.credit_note_v2'; //default since e-invoice implementation
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
if($transaction->type === TransactionType::REFUND){
//Retrieve TransactionType::CREDIT_NOTE
$booking = $transaction->owner->booking;
$kvp = $transaction->attributesKVP()->latest()->first();
if($kvp){
if($kvp->key === 'App\Models\Transaction'){
$transaction = $this->fetchesTransaction->execute(['id' => $kvp->value ]);
}
}
}
else{
//For Old Cases
$booking = $transaction->booking;
$pdfTemplateName = 'pages.pdfs.credit_note'; //default
//For New Cases with e-invoice: Retrieve the refund transaction for this credit note
$kvp = KeyValuePair::where('key', 'App\Models\Transaction')->where('value', $transaction->id)->first();
if($kvp){
$kvpOwner = $kvp->owner;
if($kvpOwner && $kvpOwner instanceof Transaction && $kvpOwner->type === TransactionType::REFUND){
$booking = $kvpOwner->owner->booking;
}
}
}
$date = $transaction->created_at;
$supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);
$brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$eInvoiceStarted = false;
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
$bookingCreatedDate = Carbon::parse($booking->created_at);
if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) {
$eInvoiceStarted = true;
}
// $eInvoiceStarted = false; //cief todo: 90 - for testing
if($eInvoiceStarted)
{
if($supplier->e_invoice === 1){
Log::info('Based on booking created date, E-Credit Note started and company wants e-invoice ' . json_encode($booking));
$date = $booking->updated_at->copy()->endOfMonth();
$pdfTemplateName = 'pages.pdfs.e_credit_note';
}
else{
Log::info('Based on booking created date, E-Credit Note started and company do not wants e-invoice');
$pdfTemplateName = 'pages.pdfs.credit_note_v2';
}
}
else{
Log::info('Based on booking created date, E-Credit Note not yet started');
}
$pdf = LaravelMpdf::loadView($pdfTemplateName, ['transaction' => $transaction, 'booking' => $booking, 'supplier' => $supplier, 'date' => $date, 'brn' => $brn,]);
$exportFileName = 'CreditNote.pdf';
$filesystemDriver = Storage::getDefaultDriver();
if($filesystemDriver === 's3'){
$pdfContent = $pdf->output();
return response([ 'src' => AWSS3Helper::S3PDF($exportFileName, $pdfContent) ]);
}
else{
return $pdf->stream($exportFileName);
}
}
}
@@ -16,6 +16,7 @@ use Illuminate\Http\Request;
use App\Classes\Modules\Wallets\Processors\CreditWalletProcessor;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
use App\Classes\ValueObjects\Constants\RemarkRefundReason;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Support\Facades\Auth;
@@ -86,9 +87,10 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
if(auth()->user()->type === 3) {
throw new MalformedRequestException('You do not have the permission to refund the order.');
}
//cief todo: 90 - move this into rules
// if(auth()->user()->type === 3) {
// throw new MalformedRequestException('You do not have the permission to refund the order.');
// }
$refundTransaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
@@ -100,14 +102,21 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
$booking = $paymentTransaction->owner;
$reference = $paymentTransaction->amount - $refundTransaction->amount < 0.01 ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking;
// $reference = $paymentTransaction->amount - $refundTransaction->amount < 0.01 ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking;
if ($paymentTransaction->amount - $refundTransaction->amount < 0.01) {
$reference = 'Return Inward for Ref. ' . $booking->marking;
} else {
$remarkGroup = RemarkRefundReason::REFUND_REASONS[$request->input('refundRemark')] ?? '';
$reference = $remarkGroup ? $remarkGroup . ' for Ref. ' . $booking->marking : $request->input('refundRemark'). ' for Ref. ' . $booking->marking;
}
$refundAmount = $this->calculatesBookingRefundAmount->calculateRefundAmount($paymentTransaction, $booking->fix_currency_id);
$paidAmount = $paymentTransaction->original_amount - $refundAmount;
if ($refundTransaction->status == ApprovalStatus::APPROVED) {
$this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference);
$this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference, $refundTransaction);
$po_transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first();
if ($po_transaction) {
@@ -129,4 +138,4 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic
return $this->response([]);
}
}
}
@@ -48,13 +48,23 @@ class CreateInvoiceDocumentProcessor
// calculate current Paid Amount
$booking = $transaction->owner_type == Booking::class ? $transaction->owner : null;
$currentPaidAmount = null;
$lastPaymentDate = $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $purchaseOrder->booking->created_at;
$brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first();
$documentDate = $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $purchaseOrder->booking->created_at;
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
if ($booking) {
$bookingCreatedDate = Carbon::parse($booking->created_at);
if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) {
$lastPaymentDate = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first()->created_at;
$lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first();
$documentDate = $lastPaymentTransaction->created_at;
if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){
$documentDate = $booking->updated_at;
}
}
if($document_type === DocumentType::EINVOICE){
$lastDayOfMonth = $documentDate->copy()->endOfMonth();
$documentDate = $lastDayOfMonth;
}
$payment = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->first();
$refundAmount = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->sum('amount');
@@ -64,7 +74,7 @@ class CreateInvoiceDocumentProcessor
$lowercaseDocumentType = strtolower($document_type);
$order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier, 'voucher_redemption' => $voucherRedemption, 'current_paid_amount' => $currentPaidAmount, 'last_payment_date' => $lastPaymentDate ]);
$order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier, 'voucher_redemption' => $voucherRedemption, 'current_paid_amount' => $currentPaidAmount, 'document_date' => $documentDate, 'brn' => $brn, 'autocountId' => null]); //cief todo: 90 - autocount id to be updated
if($purchaseOrder && $purchaseOrder->booking->service_id === 4) {
$purchaseOrderDocuments = $purchaseOrder->booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get();
@@ -20,6 +20,7 @@ use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Booking;
use App\Models\SegmentConstant;
use Carbon\Carbon;
class CreateInvoiceTransactionProcessor
{
@@ -83,10 +84,11 @@ class CreateInvoiceTransactionProcessor
/**
* @param Booking $booking
* @param String $invoiceNo
* @return void
* @throws MalformedRequestException
*/
public function execute(Booking $booking)
public function execute(Booking $booking, String $invoiceNo= "")
{
if ($booking->status === ApprovalStatus::COMPLETED) {
@@ -121,10 +123,26 @@ class CreateInvoiceTransactionProcessor
// ->first();
$transaction = $booking->transactions()
->where('type', TransactionType::PAYMENT)
->latest()->get()[0];
->where('type', TransactionType::PAYMENT)
->latest()->get()[0];
$supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);
$billNumber = $this->generatesTransactionBillNumber->execute('INV-');
// Check if eInvoice implementation has started and company opted in for eInvoice
$eInvoice = false;
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
$bookingCreatedDate = Carbon::parse($booking->created_at);
if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $supplier->e_invoice === 1) {
$eInvoice = true;
}
// $eInvoice = true; //cief todo: 90 - for testing
if($invoiceNo){
$billNumber = $invoiceNo;
}
else{
$billNUmberPrefix = $eInvoice ? 'EINV-' : 'INV-';
$billNumber = $this->generatesTransactionBillNumber->execute($billNUmberPrefix);
}
$booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::PAYMENT);
@@ -138,6 +156,7 @@ class CreateInvoiceTransactionProcessor
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->sum('tax');
$transaction_object = new TransactionObject(
$billNumber,
TransactionType::INVOICE,
@@ -159,16 +178,22 @@ class CreateInvoiceTransactionProcessor
$voucherRedemption = $transaction->voucherRedemption;
$supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);
// purchase order
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption);
// deliver order
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption);
// e-invoice
if ($eInvoice)
{
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption);
}
// invoice
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption);
else
{
$this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption);
}
$billNumber = $this->generatesTransactionBillNumber->execute('SPDO-');
@@ -21,6 +21,10 @@ use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Booking;
use App\Models\SegmentConstant;
/**
* @deprecated This class is deprecated and should not be used.
* Use `CreateInvoiceTransactionProcessor` instead or write a new one based on CreateInvoiceTransactionProcessor
*/
class CreateInvoiceTransactionWithInvoiceNoProcessor
{
@@ -53,7 +57,7 @@ class CreateInvoiceTransactionWithInvoiceNoProcessor
/**
* CreateInvoiceTransactionProcessor constructor.
* CreateInvoiceTransactionWithInvoiceNoProcessor constructor.
* @param ListsTransactions $listsTransactions
* @param CreatesTransaction $createsTransaction
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
@@ -2,6 +2,7 @@
namespace App\Classes\Modules\Wallets\Processors;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\Wallet;
use App\Models\Company;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
@@ -14,6 +15,8 @@ use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Models\Transaction;
class CreditWalletProcessor
{
@@ -32,6 +35,9 @@ class CreditWalletProcessor
/** @var UpdatesWallet */
private $updatesWallet;
/** @var CreatesKeyValuePair */
private $createsKeyValuePair;
/**
* CreateWalletLogic constructor.
* @param GeneratesWalletCode $generatesWalletCode
@@ -39,13 +45,15 @@ class CreditWalletProcessor
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatesTransaction $createsTransaction
* @param UpdatesWallet $updatesWallet
* @param CreatesKeyValuePair $createsKeyValuePair
*/
public function __construct(
GeneratesWalletCode $generatesWalletCode,
CreatesWallet $createsWallet,
GeneratesTransactionBillNumber $generatesTransactionBillNumber,
CreatesTransaction $createsTransaction,
UpdatesWallet $updatesWallet
UpdatesWallet $updatesWallet,
CreatesKeyValuePair $createsKeyValuePair
)
{
$this->generatesWalletCode = $generatesWalletCode;
@@ -53,6 +61,7 @@ class CreditWalletProcessor
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createsTransaction = $createsTransaction;
$this->updatesWallet = $updatesWallet;
$this->createsKeyValuePair = $createsKeyValuePair;
}
@@ -61,10 +70,11 @@ class CreditWalletProcessor
* @param int $transactionType
* @param float $amount
* @param string $reference
* @param $relatedTransaction
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Company $company, int $transactionType, float $amount, string $reference)
public function execute(Company $company, int $transactionType, float $amount, string $reference, $relatedTransaction = null)
{
if (!$company->wallets()->first()) {
$object = new WalletObject($company->id, 1, $this->generatesWalletCode->execute());
@@ -75,16 +85,26 @@ class CreditWalletProcessor
$wallet = $company->wallets()->first();
$billNumber = $this->generatesTransactionBillNumber->execute($transactionType === 2 ? 'DEBIT-NOTE-' : 'CREDIT-NOTE-');
$transaction_object = new TransactionObject($billNumber, $transactionType === 2 ? TransactionType::DEBIT_NOTE : TransactionType::CREDIT_NOTE, 1, $wallet->owner->id, 1, PaymentMethodType::CASH, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::APPROVED, [], $reference);
$transaction = $this->createsTransaction->execute($wallet, $transaction_object);
$updateWalletAmount = $transactionType === 2 ? ($wallet->amount - $transaction->amount) : ($wallet->amount + $transaction->amount);
$walletObject = new WalletObject($wallet->owner->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
$wallet = $this->updatesWallet->execute($wallet, $walletObject);
if($relatedTransaction && $relatedTransaction instanceof Transaction){
$kvp = $relatedTransaction->attributesKVP()->where('key', 'App\Models\Transaction')->where('value', $transaction->id)->latest()->first();
if(!$kvp){
$keyValuePairObject = new KeyValuePairObject(
"App\Models\Transaction",
$transaction->id
);
$this->createsKeyValuePair->execute($relatedTransaction, $keyValuePairObject);
}
}
return $wallet;
}
}
@@ -29,4 +29,5 @@ final class DocumentType {
public const BILL_GROUP_PAYMENT_PROOF = 'BILL_GROUP_PAYMENT_PROOF';
public const RECEIPT_VOUCHER = 'RECEIPT_VOUCHER';
public const EINVOICE = 'E_INVOICE'; //cief todo: 90 - why is there no E-CREDITNOTE
}
@@ -0,0 +1,16 @@
<?php
namespace App\Classes\ValueObjects\Constants;
class RemarkRefundReason
{
public const REFUND_REASONS = [
'Not enough stock' => 'Return Inward',
'Goods Damage/ Loss Compensation' => 'Return Inward',
'Cancel Partial Order' => 'Return Inward',
'Overpaid due to Supplier amend price' => 'Discount Allowed',
'Defective Item' => 'Discount Allowed',
'Cancel Full Order' => 'Return Inward',
'Others' => '',
];
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\RegenerateInvoiceBookingLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class RegenerateBookingEInvoiceController
{
/**
* @param Request $request
* @param RegenerateInvoiceBookingLogic $logic
* @return JsonResponse
*/
public function regenerate(Request $request, RegenerateInvoiceBookingLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Remarks;
use App\Classes\ValueObjects\Constants\RemarkRefundReason;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListRefundRemarksController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function list(Request $request): JsonResponse {
// $allReasons = RemarkRefundReason::REFUND_REASONS;
// $returnArray = [];
// foreach ($allReasons as $reason => $category) {
// $returnArray[] = [
// 'name' => $reason
// ];
// }
// $row['payload']["data"] = $returnArray;
$allReasons = RemarkRefundReason::REFUND_REASONS;
$row['payload']['data'] = array_keys($allReasons);
return response()->json($row);
}
}
@@ -5,11 +5,15 @@ namespace App\Http\Controllers\Transactions;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\GenerateCreditNotePdfLogic;
use Illuminate\Http\JsonResponse;
use App\Classes\Modules\Transactions\ControllersLogic\GenerateCreditNotePdfV2Logic;
class GenerateCreditNotePdfController
{
public function download(Request $request, GenerateCreditNotePdfLogic $logic) {
return $logic->execute($request);
}
public function downloadV2(Request $request, GenerateCreditNotePdfV2Logic $logic) {
return $logic->execute($request);
}
}
+7 -1
View File
@@ -27,9 +27,14 @@ class BookingResource extends JsonResource
$eInvoice = false;
$eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00'));
$bookingCreatedDate = Carbon::parse($this->created_at);
if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) {
$eInvoiceRequestedDate = Carbon::parse($this->company->e_invoice_requested_at);
//cief todo: 90 - for testing
if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) { //&& $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 480 cief todo: 90
$eInvoice = true;
}
// if ($this->company->e_invoice === 1) {
// $eInvoice = true;
// }
return [
'id' => $this->id,
'company' => new CompanyResource($this->company),
@@ -48,6 +53,7 @@ class BookingResource extends JsonResource
'purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->first()),
'delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->first()),
'invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->first()),
'e_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::EINVOICE)->latest()->first()),
'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()),
+5
View File
@@ -0,0 +1,5 @@
<?php
return [
'qr_code_img_url' => 'https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=',
];
@@ -6,7 +6,7 @@
<div class="row">
<div class="col p-t-10 p-b-10 p-r-0 pointer" @click="clickExpand()" :class="[{'bg-master-lighter': item.status === 1 && item.type !== 6}, {'bg-white': item.status !== 1 && item.status !== 4}, {'bg-warning-lighter': item.status === 7}, {'bg-warning-lighter': item.type === 6}]">
<div class="row m-b-5">
<div class="col-auto">
<div class="col-auto p-r-0">
<div class="font-heading fs-8 muted all-caps">Status</div>
<div class="font-heading fs-10 bold" v-if="item.type === 1" :class="[{'text-danger': item.status === 1 || item.status === 4}, {'text-success': item.status !== 1 && item.status !== 4 && item.status !== 7}, {'text-danger': item.status === 7}]">
{{ item.status === 7 ? 'Refunded' : (item.status === 1 ? 'Pending Verification' : item.status === 4 ? 'Rejected' : 'Payment Approved')}}
@@ -15,13 +15,13 @@
{{ item.status === 1 ? 'Pending Verification' : item.status === 4 ? 'Rejected' : 'Processing Payment'}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
{{item.original_currency.short_code}} {{(Math.round((item.original_amount - item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto p-l-0" v-if="totalRefunds !== 0">
<div class="col-auto" v-if="totalRefunds !== 0">
<div class="font-heading fs-8 muted all-caps">Refunded Amount</div>
<div class="font-heading fs-10 bold text-danger">
{{item.original_currency.short_code}} {{(Math.round((item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
@@ -45,7 +45,7 @@
</div>
</div>
</div>
<div class="col-auto bg-success m-r-5" v-if="item.receipt_voucher">
<div class="col-auto bg-success" v-if="item.receipt_voucher">
<document-file-viewer-component class="h-100" :file="item.receipt_voucher.files[0]">
<template slot="button">
<div class="row align-items-center h-100">
@@ -84,13 +84,13 @@
{{ item.transaction_bill.status === 1 ? 'Processing Payment' : 'Transferred'}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="col-auto">
<div class="font-heading fs-8 muted all-caps">Payment Amount</div>
<div class="font-heading fs-10 bold">
{{item.original_currency.short_code}} {{(Math.round((item.original_amount - item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto p-l-0 text-danger" v-if="totalRefunds !== 0">
<div class="col-auto text-danger" v-if="totalRefunds !== 0">
<div class="font-heading fs-8 muted all-caps">Refunded Amount</div>
<div class="font-heading fs-10 bold">
{{item.original_currency.short_code}} {{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
@@ -329,11 +329,23 @@
</div>
</div>
</div>
<div class="row m-t-10" v-show="showEditBookingAmount">
<div class="col">
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border requestModal" data-type="editBookingAmount">Edit Booking Amount</button>
<!-- <div class="col-auto text-right">
<div class="font-heading fs-12"><i class="fa fa-edit fs-12 pointer fa-fw requestModal" data-type="editBookingAmount" v-if="$store.getters.isSuperAdmin || ($store.getters.isCustomer && $store.getters.getCompanyId === 199)"></i> {{this.data.fixed_currency.short_code}} {{(Math.round((this.data.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div> -->
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="editBookingAmount">
<edit-booking-amount-form-component :data="this.data.booking" :section="section"></edit-booking-amount-form-component>
</modal-component>
</div>
</div>
<div class="row m-t-10" v-show="[2, 3].includes(item.status) && (totalRequestedRefund + totalRefunds) < data.original_amount">
<div class="col" v-if="$store.getters.isAdmin">
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border requestModal" data-type="transferSummary">Request Refund</button>
<div class="col">
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border requestModal" data-type="transferSummary">REFUND / RETURN (CREDIT NOTE)</button>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="transferSummary" size="large">
<refund-confirmation-component :data="data" :section="section" :totalRefunds="totalRequestedRefund + totalRefunds"></refund-confirmation-component>
<!-- <refund-confirmation-component :data="data" :section="section" :totalRefunds="totalRequestedRefund + totalRefunds"></refund-confirmation-component> -->
<request-credit-note-component :data="data" :section="section" :totalRefunds="totalRequestedRefund + totalRefunds"></request-credit-note-component>
</modal-component>
</div>
</div>
@@ -368,38 +380,60 @@
<div class="col bg-white padding-15">
<div class="b-b b-grey m-b-5" v-for="(refund, index) in data.transaction_refunds">
<div class="row m-b-10 parentContainer">
<div class="col-auto">
<div class="col-3">
<div class="font-heading fs-10 muted all-caps">Created At</div>
<div class="font-heading fs-10">
{{ refund.created_at }}
</div>
</div>
<div class="col-auto">
<div class="col-2">
<div class="font-heading fs-10 muted all-caps">Status</div>
<div class="font-heading fs-10">
<div class="font-heading fs-10 bold" :class="[{'text-warning': refund.status === 1}, {'text-success': refund.status === 2}, {'text-danger': refund.status === 4}]">{{ refund.status === 1 ? 'Pending Verification' : refund.status === 2 ? 'Approved' : 'Rejected'}}</div>
</div>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<span class="btn requestModal no-border" size="large" data-type="chatmodal">
<i class="fa fa-comment-o"></i>
</span>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="chatmodal">
<remark-component :section="section" :data="refund" module_type="Transaction"></remark-component>
</modal-component>
<div class="col-2">
<div class="row m-l-0 m-r-0" v-if="$store.getters.isAdmin">
<span class="btn requestModal no-border" size="large" data-type="chatmodal">
<i class="fa fa-comment-o"></i>
</span>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="chatmodal">
<remark-component :section="section" :data="refund" module_type="Transaction"></remark-component>
</modal-component>
</div>
</div>
<div class="col text-right">
<!-- With Credit Note PDF Download - Start -->
<div class="col-3 text-right" v-if="showDownloadCreditNote && refund.status === 2">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-10">
<div class="font-heading fs-10">{{refund.currency.short_code}} {{(Math.round((refund.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-14 text-success bold">
<div class="font-heading fs-10">{{refund.original_currency.short_code}} {{(Math.round((refund.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="col-2" v-if="showDownloadCreditNote && refund.status === 2">
<div class="row no-margin justify-content-end">
<div class="font-heading all-caps fs-10 m-b-5 text-right">Credit Note</div>
<a target=_blank @click="downloadCreditNote(refund.id)">
<div class="icon-thumbnail fs-11 text-white icon-25 bg-primary btn-rounded float-left m-r-0 pointer">
<i class="fa fa-file-image-o fs-10"></i>
</div>
</a>
</div>
</div>
<!-- With Credit Note PDF Download - Ends -->
<!-- Without Credit Note PDF Download - Start -->
<div class="col-5 text-right" v-else>
<div class="font-heading fs-10 muted all-caps">Amount</div>
<div class="font-heading fs-10">
<div class="font-heading fs-10">{{refund.currency.short_code}} {{(Math.round((refund.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
<div class="font-heading fs-14 text-success bold">
<div class="font-heading fs-10">{{refund.original_currency.short_code}} {{(Math.round((refund.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<!-- Without Credit Note PDF Download - Ends -->
</div>
<div class="row m-b-15 text-right parentContainer" v-if="$store.getters.isSuperAdmin && refund.status === 1">
<div class="col">
@@ -472,6 +506,7 @@
bank_id: 1
},
section: 'bookingDetailSection',
eInvoiceStartDate: window.E_INVOICE_START_DATE || ''
}
},
computed: {
@@ -512,6 +547,14 @@
hasRefundInProgress() {
var refundTransactionsStatus = this.data.transaction_refunds.length > 0 ? this.data.transaction_refunds.map(refund => refund.status) : [];
return refundTransactionsStatus.includes(0) || refundTransactionsStatus.includes(1)
},
showEditBookingAmount(){
return this.data.booking.company.employee.status === 2 && this.data.booking.company.status === 2 && (Math.round((this.data.booking.outstanding_amount + Number.EPSILON) * 100) / 100) > 0;
},
showDownloadCreditNote() {
const today = new Date();
const einvoiceStartDate = new Date(this.eInvoiceStartDate);
return today > einvoiceStartDate;
}
},
methods: {
@@ -531,6 +574,26 @@
paymentMethodArray[5] = 'Payment Gateway';
return paymentMethodArray[paymentMethod];
},
downloadCreditNote(transactionId) {
let url = this.route('transaction.credit_note.download.v2', transactionId);
if(window.LARAVEL_VAPOR_ENABLED){
this.$store.dispatch('crudRequest', {endpoint: url, method: 'get'})
.then(response =>
{
let success = response.ok;
response.json().then(response => {
if(!success){return;}
if (response.src) {
window.open(response.src, '_blank');
}
});
}
);
}
else{
window.open(url, '_blank');
}
},
},
mixins: [componentHandler]
}
@@ -0,0 +1,175 @@
<template>
<div class="row zig-zag-top" v-if="refund_reasons">
<div class="col bg-white padding-25">
<div class="row p-b-10">
<div class="col">
<div class="font-heading all-caps bold fs-10">Request Credit Note</div>
</div>
</div>
<div class="row m-b-10">
<div class="col-7">
<div class="row p-l-15">
<div v-for="(method, index) in refundMethods" :key="index"
class="col p-t-20 p-b-20 bg-master-lightest text-center b-grey pointer all-caps"
:class="{ 'bg-complete text-white': method.name === refundMethod.name }"
@click="updateRefundType(method)">
{{ method.name }}
</div>
</div>
</div>
</div>
<div class="row m-r-0 m-b-10" v-if="refundMethod.name === 'Partial Amount'">
<div class="col">
<validation-wrapper-component :validator="$v.refundAmount">
<label>Credit Note Amount</label>
<input class="form-control" name="amount" v-model="refundAmount"
:disabled="refundMethod.name === 'Full Amount'" v-money="moneyV2">
</validation-wrapper-component>
</div>
<div class="col-auto b-r b-t b-b b-grey">
<div class="row h-100 align-items-center">
<div class="col">
<div class="font-heading fs-10 muted">{{ data.booking.fixed_currency.short_code }}</div>
</div>
</div>
</div>
</div>
<div class="row m-t-5 m-b-5" v-if="refundMethod.name === 'Partial Amount'">
<div class="col">
<validation-wrapper-component selectable :validator="$v.refundRemark">
<label>Reason for refund</label>
<select-component :options="refund_reasons" v-model="refundRemark"></select-component>
</validation-wrapper-component>
</div>
</div>
<div class="row m-t-5 m-b-5" v-else>
<div class="col">
<validation-wrapper-component :validator="$v.refundRemark">
<label>Remarks</label>
<input class="form-control" name="amount" v-model="refundRemark" >
</validation-wrapper-component>
</div>
</div>
<div class="row m-t-5 m-b-5" v-if="refundMethod.name === 'Partial Amount' && refundRemark === 'Others'">
<div class="col">
<validation-wrapper-component :validator="$v.refundRemarkOthers">
<label>Reason Others</label>
<input class="form-control" name="amount" v-model="refundRemarkOthers">
</validation-wrapper-component>
</div>
</div>
<div class="row m-t-10 m-b-10">
<div class="col">
<div class="font-heading all-caps fs-10 m-b-5">Paid Amount: {{ paidAmount }}</div>
<div class="font-heading all-caps fs-10 m-b-5" v-if="this.data.refunded_amount > 0">Refunded Amount: {{ (Math.round((this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2) }}</div>
<div class="font-heading all-caps fs-10 m-b-5">Refund Amount Requested: {{ refundAmount }}</div>
</div>
</div>
<div class="row">
<div class="col-auto">
<button class="btn btn-lg btn-default bg-master-lightest b-rad-none all-caps fs-12"
data-dismiss="modal">Cancel</button>
</div>
<div class="col text-right">
<button class="btn btn-lg btn-success b-rad-none all-caps fs-12" @click="submitForm()">Confirm &
Proceed</button>
</div>
</div>
</div>
</div>
</template>
<script>
import FormHandler from '../../../general/mixins/formHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
import { requiredIf, maxValue} from "vuelidate/lib/validators";
export default {
props: {
totalRefunds: {
type: Number,
default: 0,
}
},
data() {
return {
refundAmount: (Math.round((this.data.original_amount - this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2),
refundRemark: '',
refundRemarkOthers: '',
refundMethod: { name: 'Full Amount', status: false },
refundMethods: [
{ name: 'Full Amount' },
{ name: 'Partial Amount' }
],
refund_reasons: [],
validateRefundRemark: false,
}
},
validations() {
return {
refundAmount: {
maxValue: maxValue(this.refundMaxValue)
},
refundRemark: {
required: requiredIf(function () { return this.validateRefundRemark; })
},
refundRemarkOthers: {
required: requiredIf(function () { return this.refundRemark === 'Others'; })
}
}
},
computed: {
refundMaxValue() {
return (Math.round((this.data.original_amount - this.data.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2);
},
paidAmount() {
return this.data.original_amount;
},
},
created(){
this.fetchRefundReasons();
},
methods: {
fetchRefundReasons(){
this.submit(route('api.remark.list.refund_reasons'), 'get', 'refundReasonListSection', false, false);
},
successHandler(response, section){
if(section === 'refundReasonListSection'){
const reasons = Array.isArray(response.payload.data) ? [...response.payload.data] : [];
if (!this.$store.getters.isAdmin) {
const index = reasons.indexOf("Others");
if (index !== -1) {
reasons.splice(index, 1);
}
}
this.refund_reasons = reasons;
this.validateRefundRemark = true;
}
else{
this.closeModal();
this.formHandler();
}
},
submitForm() {
this.parameters.amount = this.refundAmount;
if (this.refundRemark === 'Others') {
this.parameters.refundRemark = `${this.refundRemarkOthers}`; //`${this.refundRemark}: ${this.refundRemarkOthers}`;
} else {
this.parameters.refundRemark = this.refundRemark;
}
this.submit(this.route('api.booking.refund.create', this.data.booking.id, this.data.id), 'post', this.section, true, true)
},
updateRefundType(refund) {
this.refundMethod = { ...refund, status: !this.refundMethod.status };
if (this.refundMethod.name === 'Full Amount') {
this.refundAmount = this.refundMaxValue;
}
this.refundRemark = '';
this.refundRemarkOthers = '';
},
},
mixins: [FormHandler, ModalFormHandler]
}
</script>
@@ -0,0 +1,41 @@
<template>
<div class="row">
<div class="col bg-white padding-40 b-rad-lg">
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="isLoading" ></loading-component>
<div class="row justify-content-center" v-show="!isLoading">
<div class="col">
<div class="row m-b-20">
<div class="col">
<h3 class="all-caps">Are you Sure?</h3>
<div class="fs-11">Are you sure you want to regenerate the e-invoice for this payment?</div>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-success btn-block b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-danger btn-block b-rad-none" @click="submitForm()">Confirm</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
methods: {
submitForm() {
this.submit(this.route('api.booking.einvoice.regenerate', this.data.id), 'post', this.section, true, true);
},
successHandler(){
this.closeModal();
this.$store.dispatch('reloadList', {'name': "bookingDetailSection"});
}
},
mixins: [componentHandler, ModalFormHandler]
}
</script>
File diff suppressed because one or more lines are too long
@@ -1,7 +1,9 @@
<template>
<div class="row bg-white padding-10 m-b-10 rounded">
<div class="col-3 fs-12">{{data.created_at}}</div>
<div class="col fs-12"><span v-html="data.description"></span> <a target=”_blank” v-if="[9,11].includes(data.type) " @click="downloadTransaction(data)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a></div>
<div class="col fs-12"><span v-html="data.description"></span>
<a target=_blank v-if="[9].includes(data.type)" @click="downloadTransaction(data)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a>
</div>
<div class="col-2 text-success text-center">{{[5, 9].includes(parseFloat(data.type)) ? formatValue(data.amount) : ''}}</div>
<div class="col-2 text-danger text-center">{{[1, 11].includes(parseFloat(data.type)) ? '- ' + (formatValue(data.amount)) : ''}}</div>
<div class="col-2 text-right">{{formatValue(data.running_balance)}}</div>
@@ -0,0 +1,118 @@
@extends('layouts.base_pdf')
@section('inner_content')
<br>
<htmlpageheader name="page-header">
<br><br>
@php
$credit_title = 'Credit';
$bill_no = $credit_title === 'Refund' ? str_replace('CREDIT', 'REFUND', $transaction->bill_no) : $transaction->bill_no;
@endphp
<div class="separator"><strong><i>{{ $bill_no }}</i></strong></div>
</htmlpageheader>
<table>
<tr>
<td class="header-logo">
<img src="{{ asset('images/ri_1.png') }}" alt="logo" id="logo" class="logo">
</td>
<td class="header-cief-address">
<span class="company-name">
<strong>
CIEF WORLDWIDE SDN BHD
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252<br>
TIN: C23880226040, MSIC: 46909<br>
SST: W10-2403-32000643
</td>
<td class="header-details">
<div class="title">
<strong>
{{ $transaction->type == 9 ? $credit_title : 'Debit' }} Note
</strong>
</div>
<div class="ref">Ref# {{ $booking->marking }}</div>
<div class="date">Date: {{ $date }}</div>
<div>&nbsp;</div>
</div>
</td>
<tr>
<td colspan="3" class="bill-to">
<span class="sub-title">
{{ $transaction->type == 9 ? 'Credit' : 'Debit' }} To
</span>
</td>
</tr>
<tr>
<td colspan="3" class="address">
<div class="label">
{{ $supplier->name }}
</div>
<div class="address">
@php
$addresses = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }} ,
{{ $addresses->district()->first()->name }},
{{ $addresses->postcode }}
{{ $addresses->state()->first()->name }},
{{ $addresses->country()->first()->name }}
</div>
<div>
Phone: {{ $supplier->contacts()->first()->phone }}
</div>
@if ($supplier->e_invoice === 1)
<div>Buyer TIN: {{ $supplier->tin }}</div>
@endif
</td>
</tr>
</table>
<br>
<br>
<table class="line-table" style="overflow: wrap" autosize="1">
<thead>
<tr>
<th width="5%">No</th>
<th class="description">Description</th>
<th width="10%">Quantity</th>
<th width="15%">Unit Price (RM)</th>
<th width="10%">Total Amount<br>(RM)</th>
</tr>
</thead>
<tbody>
<tr>
<td width="5%" class="center top">1</td>
<td class="description">{{ ucfirst($transaction->payment_reference) }}</td>
<td width="10%" class="center top">1</td>
<td width="15%" class="center top">
{{ number_format($transaction->amount, 2) }}
</td>
<td width="20%" class="right top">
{{ number_format($transaction->amount, 2) }}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td class="right middle">Total</td>
<td class="total right middle">
{{ number_format($transaction->amount, 2) }}
</td>
</tr>
</tfoot>
</table>
<htmlpagefooter name="page-footer">
<table width="100%">
<tr>
<td style="text-align: right; ">This is generated by computer. No signature required.</td>
<td style="text-align: right; ">Page {PAGENO} of {nbpg}</td>
</tr>
</table>
</htmlpagefooter>
@endsection
@@ -0,0 +1,147 @@
@extends('layouts.base_pdf')
@section('inner_content')
<br>
<htmlpageheader name="page-header">
<br><br>
@php
$credit_title = 'E-Credit';
$bill_no = $transaction->bill_no;
@endphp
<div class="separator"><strong><i>{{ $bill_no }}</i></strong></div>
</htmlpageheader>
<table>
<tr>
<td class="header-logo">
<img src="{{ asset('images/ri_1.png') }}" alt="logo" id="logo" class="logo">
</td>
<td class="header-cief-address">
<span class="company-name">
<strong>
CIEF WORLDWIDE SDN BHD
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252<br>
TIN: C23880226040, MSIC: 46909<br>
SST: W10-2403-32000643
</td>
<td class="header-details">
<div class="title">
<strong>
{{ $transaction->type == 9 ? $credit_title : 'Debit' }} Note
</strong>
</div>
<div class="ref">Ref# {{ $booking->marking }}</div>
<div class="date">Date: {{ $date->toDateString() }}</div>
<div>&nbsp;</div>
</div>
</td>
<tr>
<td colspan="3" class="bill-to">
<span class="sub-title">
{{ $transaction->type == 9 ? 'Credit' : 'Debit' }} To
</span>
</td>
</tr>
<tr>
<td colspan="3" class="address">
<div class="label">
{{ $supplier->name }}
@if ($brn)
(ROC: {{ $brn->reference }})
@endif
</div>
<div class="address">
@php
$addresses = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }} ,
{{ $addresses->district()->first()->name }},
{{ $addresses->postcode }}
{{ $addresses->state()->first()->name }},
{{ $addresses->country()->first()->name }}
</div>
<div>
Phone: {{ $supplier->contacts()->first()->phone }}
</div>
@if ($supplier->e_invoice === 1)
<div>Buyer TIN: {{ $supplier->tin }}</div>
@endif
</td>
</tr>
</table>
<br>
<br>
<table class="line-table" style="overflow: wrap" autosize="1">
<thead>
<tr>
<th width="5%">No</th>
<th class="description">Description</th>
<th width="10%">Quantity</th>
<th width="15%">Unit Price (RM)</th>
<th width="10%">Total Amount<br>(RM)</th>
</tr>
</thead>
<tbody>
<tr>
<td width="5%" class="center top">1</td>
<td class="description">{{ ucfirst($transaction->payment_reference) }}</td>
<td width="10%" class="center top">1</td>
<td width="15%" class="center top">
{{ number_format($transaction->amount, 2) }}
</td>
<td width="20%" class="right top">
{{ number_format($transaction->amount, 2) }}
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td class="right middle">Total</td>
<td class="total right middle">
{{ number_format($transaction->amount, 2) }}
</td>
</tr>
</tfoot>
</table>
<htmlpagefooter name="page-footer">
<table style="width: 100%; border-spacing: 0;">
<tbody>
<tr style="border-spacing: 2em;">
<td width="80%">
</td>
<td align="center" width="20%" style="float: right;">
<table width="100%">
<tbody>
<tr align="center">
<td>
<img src="{{ url(config('qr.qr_code_img_url') . 'http://e-invoice uuid link') }}" style="width: 230px; height: 230px;" />
</td>
</tr>
<tr align="center">
<td>
<h2 style="margin: 0 !important;"><strong>http://e-invoice uuid link</strong></h2>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table width="100%">
<tr>
<td style="text-align: right; ">This is generated by computer. No signature required.</td>
<td style="text-align: right; ">Page {PAGENO} of {nbpg}</td>
</tr>
</table>
</htmlpagefooter>
@endsection
@@ -0,0 +1,115 @@
@extends('layouts.base_pdf')
@section('inner_content')
<br>
<htmlpageheader name="page-header">
<br><br>
<div class="separator"><strong><i>{{ $transaction->bill_no }}</i></strong></div>
</htmlpageheader>
<table>
<!-- Header Section -->
<tr>
<td class="header-logo">
<img src="{{ asset('images/ri_1.png') }}" alt="logo" id="logo" class="logo">
</td>
<td class="header-cief-address">
<span class="company-name"><strong>CIEF WORLDWIDE SDN BHD</strong></span>
<span class="company-reg">(1134596-M)</span><br>
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252<br>
TIN: C23880226040, MSIC: 46909<br>
SST: W10-2403-32000643
</td>
<td class="header-details">
<div class="title"><strong>E-Invoice</strong></div>
<div class="number">EI#: {{ $autocountId ?? 'NONE'}}</div>
<div class="ref">Ref# {{ $po_order_transaction->booking->marking }}</div>
<div class="date">Date: {{ $document_date->toDateString() }}</div>
<div>&nbsp;</div>
</td>
</tr>
<tr>
<td colspan="3" class="bill-to">
<span class="sub-title">Bill To</span>
</td>
</tr>
<tr>
<td colspan="3" class="address">
<div class="label">{{ $supplier->name }}
@if ($brn)
(ROC: {{ $brn->reference }})
@endif
</div>
@php
$billingAddress = $supplier->addresses()->where('billing', '=', true)->first();
@endphp
<div class="address">
{{ $billingAddress->street_one }}
{{ $billingAddress->street_two }},
{{ $billingAddress->district()->first()->name }},
{{ $billingAddress->postcode }}
{{ $billingAddress->state()->first()->name }},
{{ $billingAddress->country()->first()->name }}
</div>
<div>Phone: {{ $supplier->contacts()->first()->phone }}</div>
@if ($supplier->e_invoice === 1)
<div>Buyer TIN: {{ $supplier->tin }}</div>
@endif
</td>
</tr>
</table>
<br>
<br>
<!-- Invoice Table -->
@include('pages.pdfs.purchase_order_table')
<br>
<div class="note">
<strong>Note:</strong> All items purchased are subject to our Terms & Conditions. Please refer to our official website for more information.
</div>
<br><br>
<table style="width: 100%; border-spacing: 0;">
<tbody>
<tr style="border-spacing: 2em;">
<td width="80%">
<table style="border-spacing:10px 10px;">
<tbody>
<tr>
<td style="border-bottom: solid 2p·x #000000;">
<div class="bank-info">
Please transfer the payment to:<br>
Bank: Maybank Berhad<br>
Account Name: CIEF Worldwide Sdn Bhd<br>
Account No: 568603010762<br>
</div>
</td>
</tr>
</tbody>
</table>
</td>
<td align="center" width="20%" style="float: right;">
<table width="100%">
<tbody>
<tr align="center">
<td>
<img src="{{ url(config('qr.qr_code_img_url') . 'http://e-invoice uuid link') }}" style="width: 230px; height: 230px;" />
</td>
</tr>
<tr align="center">
<td>
<h2 style="margin: 0 !important;"><strong>http://e-invoice uuid link</strong></h2>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
@endsection
+1 -1
View File
@@ -26,7 +26,7 @@
<div class="title"><strong>Invoice</strong></div>
<div class="number">EI#: {{ $transaction->bill_no }}</div>
<div class="ref">Ref# {{ $po_order_transaction->booking->marking }}</div>
<div class="date">Date: {{ $last_payment_date }}</div>
<div class="date">Date: {{ $document_date }}</div>
<div>&nbsp;</div>
</td>
</tr>
+4 -1
View File
@@ -5,7 +5,10 @@
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-TQKCPCD');</script>
<!-- End Google Tag Manager -->
<script>window.LARAVEL_VAPOR_ENABLED=@json(env('LARAVEL_VAPOR_ENABLED', false));</script>
<script>
window.E_INVOICE_START_DATE = @json(env('E_INVOICE_START_DATE', '2025-05-01 00:00:00'));
window.LARAVEL_VAPOR_ENABLED = @json(env('LARAVEL_VAPOR_ENABLED', false));
</script>
<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
<meta charset="utf-8"/>
<title>Exchange - Overseas Money Transfers</title>
+4 -1
View File
@@ -1,6 +1,7 @@
<?php
use App\Http\Controllers\Bookings\RegenerateBookingPaymentRVController;
use App\Http\Controllers\Bookings\RegenerateBookingEInvoiceController;
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Bookings'], function () {
@@ -44,5 +45,7 @@ Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Booking
Route::group(['prefix' => '{id}/receipt', 'as' => 'receipt.'], function () {
Route::post('/', [RegenerateBookingPaymentRVController::class, 'regenerate'])->name('regenerate');
});
Route::group(['prefix' => '{id}/einvoice', 'as' => 'einvoice.'], function () {
Route::post('/', [RegenerateBookingEInvoiceController::class, 'regenerate'])->name('regenerate');
});
});
+3
View File
@@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\Remarks\ListRefundRemarksController;
use Illuminate\Support\Facades\Route;
Route::group(['namespace' => 'Remarks', 'as' => 'remark.', 'prefix' => 'remark'], function () {
@@ -8,4 +9,6 @@ Route::group(['namespace' => 'Remarks', 'as' => 'remark.', 'prefix' => 'remark']
Route::post('/{id}/create', 'CreateRemarkController@create')->name('create');
Route::put('/update/{id}', 'UpdateRemarkController@update')->name('update');
Route::delete('/delete/{id}', 'DeleteRemarkController@delete')->name('delete');
Route::get('/list/refund-reasons', [ListRefundRemarksController::class, 'list'])->name('list.refund_reasons');
});
+4 -4
View File
@@ -32,7 +32,6 @@ use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Bookings\Processors\CreatePurchaseOrderFor1688OrderProcessor;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
use App\Classes\Modules\Documents\Services\DeletesDocument;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionWithInvoiceNoProcessor;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
@@ -785,7 +784,7 @@ Route::get('/invoice/fix', function(){
$existing_invoice_bill_no->forceDelete();
}
(App()->make(CreateInvoiceTransactionWithInvoiceNoProcessor::class))->execute($booking, $bill_no);
(App()->make(CreateInvoiceTransactionProcessor::class))->execute($booking, $bill_no);
dump('regenerated invoice. Booking Marking - ' . $booking->marking . '. Bill_no - ' . $bill_no . '. Old bill_no - ' . $deletedInvoice->bill_no);
LogHelper::channel('regenerateInvoice')->info('regenerated invoice. Booking Marking - ' . $booking->marking . '. Bill_no - ' . $bill_no . '. Old bill_no - ' . $deletedInvoice->bill_no);
} else {
@@ -1010,7 +1009,8 @@ Route::get('/customer/vouchers/{marking}', function ($marking) {
}
})->name('customer.reward');
Route::get('transaction/{id}/credit_note/download', 'Transactions\GenerateCreditNotePdfController@download')->name('transaction.credit_note.download');
Route::get('transaction/{id}/credit_note/download', 'Transactions\GenerateCreditNotePdfController@downloadV2')->name('transaction.credit_note.download');
Route::get('transaction/{id}/credit_note/download/v2', 'Transactions\GenerateCreditNotePdfController@downloadV2')->name('transaction.credit_note.download.v2');
Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking, $started_at, $ended_at) {
@@ -1081,7 +1081,7 @@ Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking,
$booking->transactions()->whereIn('transactions.type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->delete();
$booking->documents()->whereIn('document_type', [DocumentType::INVOICE, DocumentType::PURCHASE_ORDER, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->delete();
(App()->make(CreateInvoiceTransactionWithInvoiceNoProcessor::class))->execute($booking, $firstBillNo);
(App()->make(CreateInvoiceTransactionProcessor::class))->execute($booking, $firstBillNo);
dump('regenerated invoice. Booking Marking - ' . $booking->marking . '. Bill_no - ' . $firstBillNo . '. Old bill_no - ' . $currentInvoice->bill_no);
LogHelper::channel('regenerateInvoice')->info('regenerated invoice. Booking Marking - ' . $booking->marking . '. Bill_no - ' . $firstBillNo . '. Old bill_no - ' . $currentInvoice->bill_no);
}