Merge branch 'dillon/90-e-invoice-g-0' into vapor/staging

This commit is contained in:
Dillon Ngo
2026-01-19 14:47:37 +08:00
21 changed files with 1398 additions and 8 deletions
@@ -0,0 +1,110 @@
<?php
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;
class DateRange implements Filter
{
/**
* Apply the filter to the query.
*
* @param Builder $builder
* @param mixed $value
* @return Builder
*/
public static function apply(Builder $builder, $value)
{
$dt1 = $value[0];
$dt2 = $value[1];
$startDate = isset($dt1) && $dt1
? Carbon::createFromFormat('Y-m-d', $dt1)->startOfDay()
: Carbon::now()->subMonth()->startOfDay();
$endDate = isset($dt2) && $dt2
? Carbon::createFromFormat('Y-m-d', $dt2)->endOfDay()
: Carbon::now()->endOfDay();
$minAllowedDate = Carbon::createFromFormat('Y-m-d', '2025-07-01')->startOfDay();
if ($startDate->lt($minAllowedDate) || $endDate->lt($minAllowedDate)) {
$startDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
// 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) {
$q->where(function ($q) {
$q->whereDoesntHave('company', function ($query) {
$query->where('debtor', 'N/A NO NEED TO IMPORT');
});
})
// Bookings without refunds
->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',
]);
}
}
@@ -0,0 +1,145 @@
<?php
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;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
class DateRangeNoData implements Filter
{
/**
* Apply the filter to the query.
*
* @param Builder $builder
* @param mixed $value
* @return Builder
*/
public static function apply(Builder $builder, $value)
{
$dt1 = $value[0];
$dt2 = $value[1];
$startDate = isset($dt1) && $dt1
? Carbon::createFromFormat('Y-m-d', $dt1)->startOfDay()
: Carbon::now()->subMonth()->startOfDay();
$endDate = isset($dt2) && $dt2
? Carbon::createFromFormat('Y-m-d', $dt2)->endOfDay()
: Carbon::now()->endOfDay();
$minAllowedDate = Carbon::createFromFormat('Y-m-d', '2025-07-01')->startOfDay();
if ($startDate->lt($minAllowedDate) || $endDate->lt($minAllowedDate)) {
$startDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
// 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) {
$q->where(function ($q) {
$q->whereDoesntHave('company', function ($query) {
$query->where('debtor', 'N/A NO NEED TO IMPORT');
});
})
// Bookings without refunds
->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 ($query){
$query
->whereDoesntHave('transactions.attributesKVP', function ($subQuery) {
$subQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
})
->whereDoesntHave('attributesKVP', function ($subQuery) {
$subQuery->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 ($query){
$query
->whereDoesntHave('transactions.attributesKVP', function ($subQuery) {
$subQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
})
->whereDoesntHave('attributesKVP', function ($subQuery) {
$subQuery->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
});
});
});
})
->with([
'company',
'transactions.transactionDetails',
'transactions.voucherRedemption',
]);
}
}
@@ -0,0 +1,151 @@
<?php
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;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
class DateRangeWithData implements Filter
{
/**
* Apply the filter to the query.
*
* @param Builder $builder
* @param mixed $value
* @return Builder
*/
public static function apply(Builder $builder, $value)
{
$dt1 = $value[0];
$dt2 = $value[1];
$startDate = isset($dt1) && $dt1
? Carbon::createFromFormat('Y-m-d', $dt1)->startOfDay()
: Carbon::now()->subMonth()->startOfDay();
$endDate = isset($dt2) && $dt2
? Carbon::createFromFormat('Y-m-d', $dt2)->endOfDay()
: Carbon::now()->endOfDay();
$minAllowedDate = Carbon::createFromFormat('Y-m-d', '2025-07-01')->startOfDay();
if ($startDate->lt($minAllowedDate) || $endDate->lt($minAllowedDate)) {
$startDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
$endDate = Carbon::createFromFormat('Y-m-d', '1970-01-01')->startOfDay();
}
// 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) {
$q->where(function ($q) {
$q->whereDoesntHave('company', function ($query) {
$query->where('debtor', 'N/A NO NEED TO IMPORT');
});
})
// Bookings without refunds
->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',
]);
}
}
@@ -0,0 +1,108 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\ListsBookings;
use App\Classes\Modules\Bookings\Standards\Rules\CanListBookings;
use App\Http\Resources\AutocountSalesInvoiceBookingResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ListBookingsSalesInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Bookings with Sales Invoice',
'message' => 'You have successfully retrieved a list of Bookings with Sales Invoice'
];
}
/** @var CanListBookings */
private $canListBookings;
/** @var ListsBookings */
private $listsBookings;
/**
* ListBookingsSalesInvoiceLogic constructor.
* @param CanListBookings $canListBookings
* @param ListsBookings $listsBookings
*/
public function __construct(CanListBookings $canListBookings, ListsBookings $listsBookings)
{
$this->canListBookings = $canListBookings;
$this->listsBookings = $listsBookings;
}
public function logic(Request $request) : JsonResponse
{
// $this->canListBookings->passes(); //cief todo: 90 - apipub
$filters = $request->input('filters');
if (is_string($filters)) {
$filters = json_decode($filters, true);
}
if (!is_array($filters)) {
return response()->json([
'message' => 'Invalid filters format. Expected JSON object.',
'payload' => new \stdClass(),
], 400);
}
// Only these filters are allowed
$allowedKeys = ['per_page', 'status', 'order_by', 'date_range', 'date_range_no_data', 'date_range_with_data'];
$extra = array_diff(array_keys($filters), $allowedKeys);
if (!empty($extra)) {
return response()->json([
'message' => 'Invalid filter(s) provided: ' . implode(', ', $extra),
'payload' => new \stdClass(),
], 400);
}
// Required filters that must always exist
$alwaysRequired = ['per_page', 'status'];
$missing = array_diff($alwaysRequired, array_keys($filters));
if (!empty($missing)) {
return response()->json([
'message' => 'Missing required filter(s): ' . implode(', ', $missing),
'payload' => new \stdClass(),
], 400);
}
if ((int) $filters['status'] !== 3) {
return response()->json([
'message' => 'Invalid status value.',
'payload' => new \stdClass(),
], 400);
}
// Required at least one of: date_range or date_range_no_data
if (!isset($filters['date_range']) && !isset($filters['date_range_no_data']) && !isset($filters['date_range_with_data'])) {
return response()->json([
'message' => 'Either "date_range" or "date_range_no_data" or "date_range_with_data" filter is required.',
'payload' => new \stdClass(),
], 400);
}
$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)]);
}
$query = $this->listsBookings->execute($this->listsBookings->deserializeFilters($request->input('filters')));
return $this->collectionResponse(AutocountSalesInvoiceBookingResource::collection($query));
}
}
@@ -0,0 +1,93 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\ProcessSalesInvoiceReportV2CommandJob;
use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingSalesInvoiceDTO;
use App\Classes\Modules\Bookings\Standards\Rules\CanUpdateBookingSalesInvoice;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class UpdateBatchBookingSalesInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Updated Bookings with Sales Invoices',
'message' => 'You have successfully updated multiple bookings with Sales Invoices',
];
}
/** @var CanUpdateBookingSalesInvoice */
private $canUpdateBookingSalesInvoice;
/**
* UpdateBatchBookingSalesInvoiceLogic constructor.
* @param CanUpdateBookingSalesInvoice $canUpdateBookingSalesInvoice
*/
public function __construct(
CanUpdateBookingSalesInvoice $canUpdateBookingSalesInvoice
) {
$this->canUpdateBookingSalesInvoice = $canUpdateBookingSalesInvoice;
}
/**
* Handles batch update for multiple booking sales invoices
*
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request): JsonResponse
{
$collections = $request->input('collections', []);
if (!is_array($collections) || empty($collections)) {
return response()->json([
'error' => 'Invalid or empty collections array provided.'
], 400);
}
$jobs = [];
$processed = [];
foreach ($collections as $index => $bookingData) {
try {
$data = [
'docno' => $bookingData['docno'] ?? $bookingData['DocNo'] ?? null,
'docdate' => $bookingData['docdate'] ?? $bookingData['DocDate'] ?? null,
'debtorcode' => $bookingData['debtorcode'] ?? $bookingData['DebtorCode'] ?? null,
'ref' => $bookingData['ref'] ?? $bookingData['Ref'] ?? null,
'shipinfo' => $bookingData['shipinfo'] ?? $bookingData['ShipInfo'] ?? null,
'accno' => $bookingData['accno'] ?? $bookingData['AccNo'] ?? null,
'detaildescription' => $bookingData['detaildescription'] ?? $bookingData['DetailDescription'] ?? null,
'furtherdescription' => $bookingData['furtherdescription'] ?? $bookingData['FurtherDescription'] ?? null,
'classification' => $bookingData['classification'] ?? $bookingData['Classification'] ?? null,
'deptno' => $bookingData['deptno'] ?? $bookingData['DeptNo'] ?? null,
'qty' => $bookingData['qty'] ?? $bookingData['Qty'] ?? null,
'unitprice' => $bookingData['unitprice'] ?? $bookingData['UnitPrice'] ?? null,
'submiteinvoice' => $bookingData['submiteinvoice'] ?? $bookingData['SubmitEinvoice'] ?? null,
'consolidatedeinvoice' => $bookingData['consolidatedeinvoice'] ?? $bookingData['ConsolidatedEinvoice'] ?? null,
'einvoicevalidationlink' => $bookingData['einvoicevalidationlink'] ?? $bookingData['EInvoiceValidationLink'] ?? null,
];
$dto = new UpdateBookingSalesInvoiceDTO($data);
$this->canUpdateBookingSalesInvoice->passes($dto);
ProcessSalesInvoiceReportV2CommandJob::dispatch($dto->toArray());
} catch (\Throwable $e) {
Log::error("Failed to process booking at index {$index}: " . $e->getMessage());
}
}
return $this->response([]);
}
}
@@ -0,0 +1,74 @@
<?php
namespace App\Classes\Modules\Bookings\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\ProcessSalesInvoiceReportV2CommandJob;
use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingSalesInvoiceDTO;
use App\Classes\Modules\Bookings\Standards\Rules\CanUpdateBookingSalesInvoice;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class UpdateBookingSalesInvoiceLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated Booking with Sales Invoice',
'message' => 'You have successfully updated Booking with Sales Invoice'
];
}
/** @var CanUpdateBookingSalesInvoice */
private $canUpdateBookingSalesInvoice;
/**
* UpdateBookingSalesInvoiceLogic constructor.
* @param CanUpdateBookingSalesInvoice $canUpdateBookingSalesInvoice
*/
public function __construct(
CanUpdateBookingSalesInvoice $canUpdateBookingSalesInvoice
)
{
$this->canUpdateBookingSalesInvoice = $canUpdateBookingSalesInvoice;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$data = [
'docno' => $request->input('docno', $request->input('DocNo')),
'docdate' => $request->input('docdate', $request->input('DocDate')),
'debtorcode' => $request->input('debtorcode', $request->input('DebtorCode')),
'ref' => $request->input('ref', $request->input('Ref')),
'shipinfo' => $request->input('shipinfo', $request->input('ShipInfo')),
'accno' => $request->input('accno', $request->input('AccNo')),
'detaildescription' => $request->input('detaildescription', $request->input('DetailDescription')),
'furtherdescription' => $request->input('furtherdescription', $request->input('FurtherDescription')),
'classification' => $request->input('classification', $request->input('Classification')),
'deptno' => $request->input('deptno', $request->input('DeptNo')),
'qty' => $request->input('qty', $request->input('Qty')),
'unitprice' => $request->input('unitprice', $request->input('UnitPrice')),
'submiteinvoice' => $request->input('submiteinvoice', $request->input('SubmitEinvoice')),
'consolidatedeinvoice' => $request->input('consolidatedeinvoice', $request->input('ConsolidatedEinvoice')),
'einvoicevalidationlink' => $request->input('einvoicevalidationlink', $request->input('EInvoiceValidationLink')),
];
$dto = new UpdateBookingSalesInvoiceDTO($data);
$this->canUpdateBookingSalesInvoice->passes($dto);
ProcessSalesInvoiceReportV2CommandJob::dispatch($dto->toArray());
return $this->response([]);
}
}
@@ -0,0 +1,184 @@
<?php
namespace App\Classes\Modules\Bookings\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UpdateBookingSalesInvoiceDTO implements DataTransferObject
{
private ?string $docNo;
private ?string $docDate;
private ?string $debtorCode;
private ?string $ref;
private ?string $shipInfo;
private ?string $accNo;
private ?string $detailDescription;
private ?string $furtherDescription;
private ?string $classification;
private ?string $deptNo;
private float $qty;
private float $unitPrice;
private bool $submitEinvoice;
private bool $consolidatedEinvoice;
private ?string $einvoiceValidationLink;
public function __construct(array $data)
{
$this->docNo = $data['docno'];
$this->docDate = $data['docdate'];
$this->debtorCode = $data['debtorcode'];
$this->ref = $data['ref'] ?? null;
$this->shipInfo = $data['shipinfo'] ?? null;
$this->accNo = $data['accno'] ?? null;
$this->detailDescription = $data['detaildescription'] ?? null;
$this->furtherDescription = $data['furtherdescription'] ?? null;
$this->classification = $data['classification'] ?? null;
$this->deptNo = $data['deptno'] ?? null;
$this->qty = (float) ($data['qty'] ?? 0);
$this->unitPrice = (float) ($data['unitprice'] ?? 0);
$this->submitEinvoice = filter_var($data['submiteinvoice'] ?? false, FILTER_VALIDATE_BOOLEAN);
$this->consolidatedEinvoice = filter_var($data['consolidatedeinvoice'] ?? false, FILTER_VALIDATE_BOOLEAN);
$this->einvoiceValidationLink = $data['einvoicevalidationlink'] ?? null;
}
/**
* @return string|null
*/
public function getDocNo(): ?string
{
return $this->docNo;
}
/**
* @return string|null
*/
public function getDocDate(): ?string
{
return $this->docDate;
}
/**
* @return string|null
*/
public function getDebtorCode(): ?string
{
return $this->debtorCode;
}
/**
* @return string|null
*/
public function getRef(): ?string
{
return $this->ref;
}
/**
* @return string|null
*/
public function getShipInfo(): ?string
{
return $this->shipInfo;
}
/**
* @return string|null
*/
public function getAccNo(): ?string
{
return $this->accNo;
}
/**
* @return string|null
*/
public function getDetailDescription(): ?string
{
return $this->detailDescription;
}
/**
* @return string|null
*/
public function getFurtherDescription(): ?string
{
return $this->furtherDescription;
}
/**
* @return string|null
*/
public function getClassification(): ?string
{
return $this->classification;
}
/**
* @return string|null
*/
public function getDeptNo(): ?string
{
return $this->deptNo;
}
/**
* @return float
*/
public function getQty(): float
{
return $this->qty;
}
/**
* @return float
*/
public function getUnitPrice(): float
{
return $this->unitPrice;
}
/**
* @return bool
*/
public function getSubmitEinvoice(): bool
{
return $this->submitEinvoice;
}
/**
* @return bool
*/
public function getConsolidatedEinvoice(): bool
{
return $this->consolidatedEinvoice;
}
/**
* @return string|null
*/
public function getEinvoiceValidationLink(): ?string
{
return $this->einvoiceValidationLink;
}
public function toArray(): array
{
return [
'docno' => $this->docNo,
'docdate' => $this->docDate,
'debtorcode' => $this->debtorCode,
'ref' => $this->ref,
'shipinfo' => $this->shipInfo,
'accno' => $this->accNo,
'detaildescription' => $this->detailDescription,
'furtherdescription' => $this->furtherDescription,
'classification' => $this->classification,
'deptno' => $this->deptNo,
'qty' => $this->qty,
'unitprice' => $this->unitPrice,
'submiteinvoice' => $this->submitEinvoice,
'consolidatedeinvoice' => $this->consolidatedEinvoice,
'einvoicevalidationlink' => $this->einvoiceValidationLink,
];
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Classes\Modules\Bookings\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject;
class CanListBookingsSalesInvoice extends AbstractRule
{
/**
* @return bool
*/
protected function authorized($object): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param BookingObject $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param BookingObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,54 @@
<?php
namespace App\Classes\Modules\Bookings\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Bookings\Standards\Validators\BookingSalesInvoiceValidation;
use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingSalesInvoiceDTO;
use Illuminate\Support\Facades\Auth;
class CanUpdateBookingSalesInvoice extends AbstractRule
{
/** @var BookingSalesInvoiceValidation */
private $bookingSalesInvoiceValidation;
/**
* CanUpdateBookingSalesInvoice constructor.
* @param UpdateBookingSalesInvoiceDTO $bookingSalesInvoiceValidation
*/
public function __construct(BookingSalesInvoiceValidation $bookingSalesInvoiceValidation)
{
$this->bookingSalesInvoiceValidation = $bookingSalesInvoiceValidation;
}
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @param UpdateBookingSalesInvoiceDTO $object
* @return bool
* @throws \App\Classes\Exceptions\RequestValidationException
*/
protected function validators($object): bool
{
return $this->bookingSalesInvoiceValidation->validate($object);
}
/**
* @param UpdateBookingSalesInvoiceDTO $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Bookings\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingSalesInvoiceDTO;
class BookingSalesInvoiceValidation extends AbstractValidation
{
/**
* @param UpdateBookingSalesInvoiceDTO $object
* @return array
*/
protected function data($object): array
{
return [
'docno' => $object->getDocNo(),
'docdate' => $object->getDocDate(),
'debtorcode' => $object->getDebtorCode(),
'ref' => $object->getRef(),
'shipinfo' => $object->getShipInfo(),
'accno' => $object->getAccNo(),
'detaildescription' => $object->getDetailDescription(),
'furtherdescription' => $object->getFurtherDescription(),
'classification' => $object->getClassification(),
'deptno' => $object->getDeptNo(),
'qty' => $object->getQty(),
'unitprice' => $object->getUnitPrice(),
'submiteinvoice' => $object->getSubmitEinvoice(),
'consolidatedeinvoice' => $object->getConsolidatedEinvoice(),
'einvoicevalidationlink' => $object->getEinvoiceValidationLink(),
];
}
/**
* @return array
*/
protected function rules(): array
{
return [
'docno' => 'required|string',
'docdate' => 'required|date',
'debtorcode' => 'required|string',
'ref' => 'required|string',
'shipinfo' => 'required|string',
'einvoicevalidationlink' => 'required|string',
];
}
/**
* @return array
*/
protected function messages(): array
{
return [];
}
}
@@ -82,6 +82,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
@@ -111,10 +111,6 @@ class CreateInvoiceTransactionV2Processor
// Log::info('CreateInvoiceTransactionV2Processor generateEInvoiceRefund: ' . json_encode($generateEInvoiceRefund));
// Log::info('CreateInvoiceTransactionV2Processor bookingOriginalStatus: ' . json_encode($bookingOriginalStatus));
if($generateEInvoiceRefund){
$generateEInvoice = true; //With or without refund, these 2 flags are meant to Generate E-Invoice, so cannot have opposite indicator
}
if ($booking->status === ApprovalStatus::COMPLETED && !$generateEInvoiceRefund) {
Log::info('CreateInvoiceTransactionV2Processor Check 1 Bypass New Business Logic Update for booking ' . $booking->id);
// return;
@@ -124,7 +120,7 @@ class CreateInvoiceTransactionV2Processor
$refund_amount = $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id);
$booking_amount = $booking->fix_amount;
if ((float) $booking_amount === (float) $refund_amount && !$generateEInvoice) {
if ((float) $booking_amount === (float) $refund_amount && !$generateEInvoiceRefund) {
return;
}
@@ -257,6 +253,19 @@ class CreateInvoiceTransactionV2Processor
$voucherRedemption = $transaction->voucherRedemption;
if($generateEInvoiceRefund){
$metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($metadata){
$generateEInvoice = true;
}
else{
$metadata = $transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($metadata){
$generateEInvoice = true;
}
}
}
if($purchaseOrder){
// purchase order
if(!$generateEInvoiceRefund){
@@ -46,6 +46,9 @@ class UpdateRefundTransactionStatusProcessor
/** @var CanUpdateRefundTransactionStatus */
private $canUpdateRefundTransactionStatus;
/** @var CreateInvoiceTransactionV2Processor */
private $createInvoiceTransactionV2Processor;
/**
* UpdateRefundTransactionStatusProcessor constructor.
* @param FetchesCompany $fetchesCompany
@@ -57,8 +60,9 @@ class UpdateRefundTransactionStatusProcessor
* @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount
* @param UpdateBookingAmountLogic $updateBookingAmountLogic
* @param CanUpdateRefundTransactionStatus $canUpdateRefundTransactionStatus
* @param CreateInvoiceTransactionV2Processor $createInvoiceTransactionV2Processor
*/
public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount, UpdateBookingAmountLogic $updateBookingAmountLogic, CanUpdateRefundTransactionStatus $canUpdateRefundTransactionStatus)
public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount, UpdateBookingAmountLogic $updateBookingAmountLogic, CanUpdateRefundTransactionStatus $canUpdateRefundTransactionStatus, CreateInvoiceTransactionV2Processor $createInvoiceTransactionV2Processor)
{
$this->fetchesCompany = $fetchesCompany;
$this->fetchesTransaction = $fetchesTransaction;
@@ -69,6 +73,7 @@ class UpdateRefundTransactionStatusProcessor
$this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount;
$this->updateBookingAmountLogic = $updateBookingAmountLogic;
$this->canUpdateRefundTransactionStatus = $canUpdateRefundTransactionStatus;
$this->createInvoiceTransactionV2Processor = $createInvoiceTransactionV2Processor;
}
@@ -125,5 +130,15 @@ class UpdateRefundTransactionStatusProcessor
if (!$paidAmount > 0) {
$this->updatesTransactionStatus->execute($paymentTransaction, ApprovalStatus::REFUNDED);
}
//A full refund will need invoice generated
if($refundAmount === $booking->fix_amount){
$this->createInvoiceTransactionV2Processor->execute($booking, "", null, [
'generateEInvoice' => false,
'generateEInvoiceWithNormalInvoiceTemplate' => false,
'generateEInvoiceRefund' => true,
'bookingOriginalStatus' => $booking->status
]);
}
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\ListBookingsSalesInvoiceLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListBookingsSalesInvoiceController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function list(Request $request, ListBookingsSalesInvoiceLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Bookings;
use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingSalesInvoiceLogic;
use App\Classes\Modules\Bookings\ControllersLogic\UpdateBatchBookingSalesInvoiceLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateBookingSalesInvoiceController
{
/**
* @param Request $request
* @return JsonResponse
*/
public function update(Request $request, UpdateBookingSalesInvoiceLogic $logic) : JsonResponse {
return $logic->execute($request);
}
/**
* @param Request $request
* @return JsonResponse
*/
public function updateBatch(Request $request, UpdateBatchBookingSalesInvoiceLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AutocountSalesInvoiceBookingDetailsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'DocNo' => $this['DocNo'],
'DocDate' => $this['DocDate'],
'DebtorCode' => $this['DebtorCode'],
'Ref' => $this['Ref'],
'ShipInfo' => $this['ShipInfo'],
'AccNo' => $this['AccNo'],
'DetailDescription' => $this['DetailDescription'],
'FurtherDescription' => $this['FurtherDescription'],
'Classification' => $this['Classification'],
'DeptNo' => $this['DeptNo'],
'Qty' => $this['Qty'],
'UnitPrice' => $this['UnitPrice'],
'SubmitEinvoice' => $this['SubmitEinvoice'],
'ConsolidatedEinvoice' => $this['ConsolidatedEinvoice'],
'InvoiceStatus' => $this['InvoiceStatus'],
];
}
}
@@ -0,0 +1,247 @@
<?php
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Booking;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundServiceCharge;
use App\Classes\ValueObjects\Constants\KVPKey;
use Illuminate\Http\Resources\Json\JsonResource;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class AutocountSalesInvoiceBookingResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$booking = $this;
$details = collect();
$purchaseOrder = $this->transactions->where('type', TransactionType::PURCHASE_ORDER)->first();
$company = $this->company;
$lastPaymentTransaction = $this->transactions
->where('type', TransactionType::PAYMENT)
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->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) {
// return [];
// }
if($company->e_invoice === 1){
$documentDate = $documentDate->copy()->endOfMonth();
}
$invoiceTransaction = $this->transactions->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first();
$currencyId = $this->fix_currency_id;
$subtotal = 0;
$displayedSubtotal = 0;
$totalPayment = 0;
$averageCurrencyRate = $invoiceTransaction ? $invoiceTransaction->currency_rate : 0;
$paymentSum = $this->transactions
->where('type', TransactionType::PAYMENT)
->where('status', ApprovalStatus::COMPLETED)
->sum(function ($transaction) {
return round($transaction->amount, 2);
});
if ($paymentSum){
$averageCurrencyRate = $this->transactions
->where('type', TransactionType::PAYMENT)
->where('status', ApprovalStatus::COMPLETED)
->sum(function ($transaction) {
return $transaction->currency_rate;
}) / $this->transactions
->where('type', TransactionType::PAYMENT)
->where('status', ApprovalStatus::COMPLETED)
->count();
$booking = Booking::where('id', $this->id)->first();
$refundedAmount = (App()->make(CalculatesBookingRefundAmount::class))->execute($booking, 1);
$refundedServiceCharge = (App()->make(CalculatesBookingRefundServiceCharge::class))->execute($booking, 1);
$totalPayment = $paymentSum - $refundedAmount - $refundedServiceCharge;
}
$formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y');
$docNo = '<<New>>';
$firstItem = true;
if($invoiceTransaction){
$invoiceTransactionKVP = $invoiceTransaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
if($invoiceTransactionKVP){
$docNo = $invoiceTransactionKVP->value;
}
else {
$bookingKVP = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->first();
$docNo = $bookingKVP ? $bookingKVP->value :'<<New>>';
}
}
$transactionDetails = $purchaseOrder->transactionDetails;
foreach ($transactionDetails as $detail) {
$displayUnitPrice = 0;
if($averageCurrencyRate && $currencyId){
$exactUnitPrice = ($currencyId) === 1 ? $detail->price : bcdiv($detail->price, $averageCurrencyRate, 7);
$displayUnitPrice = round($exactUnitPrice, 2);
$itemTotal = bcmul($exactUnitPrice, $detail->quantity, 5);
$displayedItemTotal = round(bcmul($displayUnitPrice, $detail->quantity, 7), 2);
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
$subtotal = bcadd($subtotal, $itemTotal, 5);
}
$detail = [
'DocNo' => $firstItem ? $docNo : '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction ? $invoiceTransaction->bill_no : '',
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
'FurtherDescription' => $detail->product_name,
'Classification' => '022',
'DeptNo' => 'C',
'Qty' => number_format($detail->quantity, 0),
'UnitPrice' => $displayUnitPrice ? number_format($displayUnitPrice, 2) : '0',
'SubmitEinvoice' => $firstItem ? 'T' : '',
'ConsolidatedEinvoice' => $firstItem ? ($company->e_invoice ? 'F' : 'T') : '',
'InvoiceStatus' => (string) $this->invoice_status,
];
$details->push($detail);
if($firstItem) {
$firstItem = false;
}
}
// 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' => '',
'InvoiceStatus' => (string) $this->invoice_status,
];
$details->push($detail);
}
// Voucherify - Ends
// Service Charge - Starts
$serviceCharge = 0;
if (!$totalPayment && $invoiceTransaction) {
$serviceCharge = $invoiceTransaction->service_charge;
}
else {
$serviceCharge = $this->transactions
->where('type', TransactionType::PAYMENT)
->where('status', ApprovalStatus::COMPLETED)
->sum(function ($transaction) {
return $transaction->service_charge;
});
}
$detail = [
'DocNo' => '',
'DocDate' => $formattedDocumentDate,
'DebtorCode' => $company->debtor,
'Ref' => $invoiceTransaction ? $invoiceTransaction->bill_no : '',
'ShipInfo' => $this->marking,
'AccNo' => '500-0000',
'DetailDescription' => 'PRODUCT NAME :',
'FurtherDescription' => 'Service Charge',
'Classification' => '022',
'DeptNo' => 'C',
'Qty' => '1',
'UnitPrice' => $serviceCharge ? number_format($serviceCharge, 2) : '0',
'SubmitEinvoice' => '',
'ConsolidatedEinvoice' => '',
'InvoiceStatus' => (string) $this->invoice_status,
];
$details->push($detail);
// Service Charge - Ends
// Adjustment - Starts
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';
$displayedTotal = bcadd(
bcadd(
bcadd($displayedSubtotal, $serviceCharge, 5),
$tax,
5
),
$voucherDiscount,
5
);
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $serviceCharge, 5), $invoiceTransaction->tax, 5), $voucherDiscount, 5);
$adjustment = bcsub($expectedTotal, $displayedTotal, 5);
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' => '',
'InvoiceStatus' => (string) $this->invoice_status,
];
$details->push($detail);
}
// Adjustment - Ends
return AutocountSalesInvoiceBookingDetailsResource::collection(
collect($details)
);
}
}
@@ -195,7 +195,7 @@
<!-- Approve and Edit Purchase Order -->
<div class="row" v-if="submitted">
<div class="col-12 col-md-5 pr-md-0" v-if="submitted && data.status !== 3">
<div class="col-12 col-md-5 pr-md-0" v-if="submitted">
<div class="row m-b-15" v-if="($store.getters.isAdmin && data.purchase_order.status === 1) || ($store.getters.isCustomer && data.purchase_order.status === 1 && $store.getters.getCompanyId === 199)" >
<div class="col">
<button class="btn btn-sm btn-block btn-success b-rad-none" :disabled="poProcessing" @click="handleRepprove()">Approve Purchase Order</button>
@@ -133,7 +133,7 @@
</div>
</div>
</div>
<div class="col" v-else>
<div class="col" v-else> <!-- Show only single E-Invoice button-->
<div class="row m-b-50">
<div class="col no-padding">
<div class="row m-t-20">
+8
View File
@@ -1,9 +1,17 @@
<?php
use App\Http\Controllers\Bookings\ListBookingsSalesInvoiceController;
use App\Http\Controllers\Bookings\UpdateBookingSalesInvoiceController;
use Illuminate\Support\Facades\Route;
Route::group(['middleware' => 'apipub', 'prefix' => 'v1', 'as' => 'apipub.'], function () {
Route::group(['middleware' => 'token.check'], function () {
Route::get('transactions/mappable/query', 'Transactions\ListMappableTransactionsController@list')->name('transaction.mappable.list');
Route::group(['prefix' => 'booking', 'as' => 'booking.'], function () {
Route::get('/sales-invoice/list', [ListBookingsSalesInvoiceController::class, 'list'])->name('booking.sales-invoice.list');
Route::post('/sales-invoice', [UpdateBookingSalesInvoiceController::class, 'update'])->name('booking.sales-invoice.update');
Route::post('/sales-invoice/batch', [UpdateBookingSalesInvoiceController::class, 'updateBatch'])->name('booking.sales-invoice.batch.update');
});
});
});