Merge branch 'dillon/90-e-invoice-f-2' into vapor/development

This commit is contained in:
Dillon Ngo
2025-11-04 08:58:05 +08:00
7 changed files with 348 additions and 118 deletions
@@ -2,6 +2,7 @@
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
@@ -34,24 +35,71 @@ class DateRange implements Filter
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
return $builder->with([
// return $builder->with([
// 'company',
// 'transactions.transactionDetails',
// 'transactions.voucherRedemption',
// ])
// ->whereHas('transactions', function ($query) use ($startDate, $endDate){
// $query->payments()
// ->complete()
// ->whereBetween('created_at', [$startDate, $endDate])
// ->latest('created_at');
// })
// ->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
// $query->payments()
// ->complete()
// ->where(function ($q) use ($startDate, $endDate) {
// $q->where('created_at', '<', $startDate)
// ->orWhere('created_at', '>', $endDate);
// });
// });
return $builder->whereIn('status', [
ApprovalStatus::APPROVED,
ApprovalStatus::COMPLETED,
ApprovalStatus::SUSPENDED,
])
->where(function ($q) use ($startDate, $endDate) {
// Bookings without refunds
$q->where(function ($q1) use ($startDate, $endDate) {
$q1->where('status', ApprovalStatus::COMPLETED)
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate]);
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
});
})
// OR bookings with refunds
->orWhere(function ($q2) use ($startDate, $endDate) {
$q2->whereHas('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->whereBetween('created_at', [$startDate, $endDate])
->whereHas('transactions', function ($refundQuery) {
$refundQuery->refunds()
->whereIn('status', [ApprovalStatus::APPROVED]);
});
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
});
});
})
->with([
'company',
'transactions.transactionDetails',
'transactions.voucherRedemption',
])
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate])
->latest('created_at');
})
->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->complete()
->where(function ($q) use ($startDate, $endDate) {
$q->where('created_at', '<', $startDate)
->orWhere('created_at', '>', $endDate);
});
});
]);
}
}
@@ -2,6 +2,7 @@
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
@@ -36,38 +37,103 @@ class DateRangeNoData implements Filter
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
return $builder->with([
// return $builder->with([
// 'company',
// 'transactions.transactionDetails',
// 'transactions.voucherRedemption',
// ])
// // ->whereHas('company', function ($query) {
// // $query->where('debtor', '!=', 'N/A NO NEED TO IMPORT');
// // })
// ->whereHas('transactions', function ($query) use ($startDate, $endDate){
// $query->payments()
// ->complete()
// ->whereBetween('created_at', [$startDate, $endDate])
// ->latest('created_at');
// })
// ->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
// $query->payments()
// ->complete()
// ->where(function ($q) use ($startDate, $endDate) {
// $q->where('created_at', '<', $startDate)
// ->orWhere('created_at', '>', $endDate);
// });
// })
// ->whereHas('transactions', function ($query) use ($startDate, $endDate){
// $query->where('type', TransactionType::INVOICE)
// ->latest('created_at')
// ->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
// $invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
// });
// })
// ->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
// $invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
// });
return $builder->whereIn('status', [
ApprovalStatus::APPROVED,
ApprovalStatus::COMPLETED,
ApprovalStatus::SUSPENDED,
])
->where(function ($q) use ($startDate, $endDate) {
// Bookings without refunds
$q->where(function ($q1) use ($startDate, $endDate) {
$q1->where('status', ApprovalStatus::COMPLETED)
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate]);
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
})
->whereHas('transactions', function ($query) {
$query->where('type', TransactionType::INVOICE)
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
// OR bookings with refunds
->orWhere(function ($q2) use ($startDate, $endDate) {
$q2->whereHas('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->whereBetween('created_at', [$startDate, $endDate])
->whereHas('transactions', function ($refundQuery) {
$refundQuery->refunds()
->whereIn('status', [ApprovalStatus::APPROVED]);
});
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
})
->whereHas('transactions', function ($query) {
$query->where('type', TransactionType::INVOICE)
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
});
})
->with([
'company',
'transactions.transactionDetails',
'transactions.voucherRedemption',
])
// ->whereHas('company', function ($query) {
// $query->where('debtor', '!=', 'N/A NO NEED TO IMPORT');
// })
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate])
->latest('created_at');
})
->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->complete()
->where(function ($q) use ($startDate, $endDate) {
$q->where('created_at', '<', $startDate)
->orWhere('created_at', '>', $endDate);
});
})
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->where('type', TransactionType::INVOICE)
->latest('created_at')
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
->whereDoesntHave('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
]);
}
}
@@ -2,6 +2,7 @@
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
@@ -36,38 +37,110 @@ class DateRangeWithData implements Filter
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
return $builder->with([
// return $builder->with([
// 'company',
// 'transactions.transactionDetails',
// 'transactions.voucherRedemption',
// ])
// // ->whereHas('company', function ($query) {
// // $query->where('debtor', '!=', 'N/A NO NEED TO IMPORT');
// // })
// ->whereHas('transactions', function ($query) use ($startDate, $endDate){
// $query->payments()
// ->complete()
// ->whereBetween('created_at', [$startDate, $endDate])
// ->latest('created_at');
// })
// ->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
// $query->payments()
// ->complete()
// ->where(function ($q) use ($startDate, $endDate) {
// $q->where('created_at', '<', $startDate)
// ->orWhere('created_at', '>', $endDate);
// });
// })
// ->whereHas('transactions', function ($query) use ($startDate, $endDate){
// $query->where('type', TransactionType::INVOICE)
// ->latest('created_at')
// ->whereHas('attributesKVP', function ($invoiceQuery) {
// $invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
// });
// });
// // ->WhereHas('attributesKVP', function ($invoiceQuery) {
// // $invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
// // });
return $builder->whereIn('status', [
ApprovalStatus::APPROVED,
ApprovalStatus::COMPLETED,
ApprovalStatus::SUSPENDED,
])
->where(function ($q) use ($startDate, $endDate) {
// Bookings without refunds
$q->where(function ($q1) use ($startDate, $endDate) {
$q1->where('status', ApprovalStatus::COMPLETED)
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate]);
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
})
->where(function ($subQuery){
$subQuery
->whereHas('transactions', function ($query) {
$query->where('type', TransactionType::INVOICE)
->whereHas('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
->orWhereHas('attributesKVP', function ($noInvoiceQuery) {
$noInvoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
});
})
// OR bookings with refunds
->orWhere(function ($q2) use ($startDate, $endDate) {
$q2->whereHas('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->whereBetween('created_at', [$startDate, $endDate])
->whereHas('transactions', function ($refundQuery) {
$refundQuery->refunds()
->whereIn('status', [ApprovalStatus::APPROVED]);
});
})
->whereDoesntHave('transactions', function ($query) {
$query->payments()
->complete()
->where(function ($q) {
$q->where('created_at', '<', '2025-07-01 00:00:00');
});
})
->where(function ($subQuery){
$subQuery
->whereHas('transactions', function ($query) {
$query->where('type', TransactionType::INVOICE)
->whereHas('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
})
->orWhereHas('attributesKVP', function ($noInvoiceQuery) {
$noInvoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
});
});
})
->with([
'company',
'transactions.transactionDetails',
'transactions.voucherRedemption',
])
// ->whereHas('company', function ($query) {
// $query->where('debtor', '!=', 'N/A NO NEED TO IMPORT');
// })
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->payments()
->complete()
->whereBetween('created_at', [$startDate, $endDate])
->latest('created_at');
})
->whereDoesntHave('transactions', function ($query) use ($startDate, $endDate) {
$query->payments()
->complete()
->where(function ($q) use ($startDate, $endDate) {
$q->where('created_at', '<', $startDate)
->orWhere('created_at', '>', $endDate);
});
})
->whereHas('transactions', function ($query) use ($startDate, $endDate){
$query->where('type', TransactionType::INVOICE)
->latest('created_at')
->whereHas('attributesKVP', function ($invoiceQuery) {
$invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
});
// ->WhereHas('attributesKVP', function ($invoiceQuery) {
// $invoiceQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
// });
]);
}
}
@@ -95,6 +95,7 @@ class ListBookingsSalesInvoiceLogic extends AbstractControllerLogic
$filters = $request->input('filters');
if (is_string($filters)) {
$decoded = json_decode($filters, true) ?? [];
unset($decoded['status']);
$decoded['order_by'] = ['column' => 'id', 'DESC' => false];
$request->merge(['filters' => json_encode($decoded)]);
}
@@ -80,6 +80,11 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR
});
}
public function getRecordCount(): int
{
return $this->query()->count();
}
/**
* @param Booking $booking
* @return array
@@ -84,6 +84,11 @@ class ExportsSalesInvoiceWithRefundReport implements FromQuery, WithHeadings, Wi
});
}
public function getRecordCount(): int
{
return $this->query()->count();
}
/**
* @param Booking $booking
* @return array
@@ -22,6 +22,7 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
*/
public function toArray($request)
{
$booking = $this;
$details = collect();
$purchaseOrder = $this->transactions->where('type', TransactionType::PURCHASE_ORDER)->first();
$company = $this->company;
@@ -32,6 +33,9 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
->sortByDesc('created_at')
->first();
if(!$lastPaymentTransaction){
$lastPaymentTransaction = $this->transactions()->payments()->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::REFUNDED])->latest()->first();
}
$documentDate = Carbon::parse($lastPaymentTransaction->created_at);
// if ($documentDate < $this->startDate || $documentDate > $this->endDate) {
@@ -49,7 +53,7 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
$subtotal = 0;
$displayedSubtotal = 0;
$totalPayment = 0;
$averageCurrencyRate = $invoiceTransaction->currency_rate;
$averageCurrencyRate = $invoiceTransaction ? $invoiceTransaction->currency_rate : 0;
$paymentSum = $this->transactions
->where('type', TransactionType::PAYMENT)
->where('status', ApprovalStatus::COMPLETED)
@@ -105,7 +109,7 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
'DocNo' => $firstItem ? $docNo : '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction->bill_no,
'Ref' => $invoiceTransaction ? $invoiceTransaction->bill_no : '',
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
@@ -124,9 +128,35 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
}
}
// Voucherify - Starts
$voucherRedemption = $lastPaymentTransaction->voucherRedemption;
if($voucherRedemption){
$voucherDiscount = $voucherRedemption ? bcmul((string)$voucherRedemption->value, "-1", 2) : "0";
$voucher = $voucherRedemption->voucher;
$category = $voucher->campaign ? $voucher->campaign->category : null;
$detail = [
'DocNo' => '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction ? $invoiceTransaction->bill_no : '',
'ShipInfo' => $this->marking,
'AccNo' => $category === 'Compensation Voucher' ? '1000-000' : '949-2000',
'DetailDescription' => 'PRODUCT NAME :',
'FurtherDescription' => $voucher->code,
'Classification' => '022',
'DeptNo' => 'C',
'Qty' => '1',
'UnitPrice' => $voucherDiscount ? number_format($voucherDiscount, 2): '0',
'SubmitEinvoice' => '',
'ConsolidatedEinvoice' => '',
];
$details->push($detail);
}
// Voucherify - Ends
// Service Charge - Starts
$serviceCharge = 0;
if (!$totalPayment) {
if (!$totalPayment && $invoiceTransaction) {
$serviceCharge = $invoiceTransaction->service_charge;
}
else {
@@ -142,7 +172,7 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
'DocNo' => '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction->bill_no,
'Ref' => $invoiceTransaction ? $invoiceTransaction->bill_no : '',
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
@@ -158,50 +188,52 @@ class AutocountSalesInvoiceBookingResource extends JsonResource
// Service Charge - Ends
// Adjustment - Starts
$adjustment = 0;
$voucherRedemption = $invoiceTransaction->voucherRedemption;
$voucherDiscount = $voucherRedemption ? bcmul((string)$voucherRedemption->value, "-1", 2) : "0";
if($invoiceTransaction){
$adjustment = 0;
$voucherRedemption = $invoiceTransaction->voucherRedemption;
$voucherDiscount = $voucherRedemption ? bcmul((string)$voucherRedemption->value, "-1", 2) : "0";
$displayedSubtotal = is_numeric($displayedSubtotal) ? sprintf('%F', $displayedSubtotal) : '0';
$serviceCharge = is_numeric($serviceCharge) ? sprintf('%F', $serviceCharge) : '0';
$tax = is_numeric($invoiceTransaction->tax) ? sprintf('%F', $invoiceTransaction->tax) : '0';
$voucherDiscount = is_numeric($voucherDiscount) ? sprintf('%F', $voucherDiscount) : '0';
$displayedSubtotal = is_numeric($displayedSubtotal) ? sprintf('%F', $displayedSubtotal) : '0';
$serviceCharge = is_numeric($serviceCharge) ? sprintf('%F', $serviceCharge) : '0';
$tax = is_numeric($invoiceTransaction->tax) ? sprintf('%F', $invoiceTransaction->tax) : '0';
$voucherDiscount = is_numeric($voucherDiscount) ? sprintf('%F', $voucherDiscount) : '0';
$displayedTotal = bcadd(
bcadd(
bcadd($displayedSubtotal, $serviceCharge, 5),
$tax,
$displayedTotal = bcadd(
bcadd(
bcadd($displayedSubtotal, $serviceCharge, 5),
$tax,
5
),
$voucherDiscount,
5
),
$voucherDiscount,
5
);
);
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $serviceCharge, 5), $invoiceTransaction->tax, 5), $voucherDiscount, 5);
$adjustment = bcsub($expectedTotal, $displayedTotal, 5);
if ($totalPayment) {
$expectedTotal = $totalPayment;
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $serviceCharge, 5), $invoiceTransaction->tax, 5), $voucherDiscount, 5);
$adjustment = bcsub($expectedTotal, $displayedTotal, 5);
}
$detail = [
'DocNo' => '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction->bill_no,
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
'FurtherDescription' => 'Adjustment',
'Classification' => '022',
'DeptNo' => 'C',
'Qty' => '1',
'UnitPrice' => $adjustment ? number_format($adjustment, 2) : '0',
'SubmitEinvoice' => '',
'ConsolidatedEinvoice' => '',
];
$details->push($detail);
if ($totalPayment) {
$expectedTotal = $totalPayment;
$adjustment = bcsub($expectedTotal, $displayedTotal, 5);
}
$detail = [
'DocNo' => '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction->bill_no,
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
'FurtherDescription' => 'Adjustment',
'Classification' => '022',
'DeptNo' => 'C',
'Qty' => '1',
'UnitPrice' => $adjustment ? number_format($adjustment, 2) : '0',
'SubmitEinvoice' => '',
'ConsolidatedEinvoice' => '',
];
$details->push($detail);
}
// Adjustment - Ends
return AutocountSalesInvoiceBookingDetailsResource::collection(