Merge remote-tracking branch 'origin/master'

This commit is contained in:
omair saleh
2022-10-11 17:48:48 +08:00
20 changed files with 412 additions and 65 deletions
@@ -16,6 +16,7 @@ use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
abstract class AbstractControllerLogic
{
@@ -66,6 +67,7 @@ abstract class AbstractControllerLogic
return $response;
} catch (ErrorException|GeneralExceptions $exception){
log::error($exception);
return (new ApiResponseObject($this->getNotificationTitle().' failed', $exception->getMessage(),
$exception->getCode() ? $exception->getCode() : HttpStatus::SERVER_ERROR))->handler();
@@ -99,4 +101,4 @@ abstract class AbstractControllerLogic
return $this->response(json_decode($collection->response()->getContent(), true));
}
}
}
@@ -6,6 +6,7 @@ namespace App\Classes\General\Eloquent;
use App\Classes\Exceptions\MalformedRequestException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
abstract class AbstractListRecord extends AbstractGetRecord
{
@@ -23,6 +24,7 @@ abstract class AbstractListRecord extends AbstractGetRecord
return $this->handler($filters);
} catch (QueryException $exception){
log::error($exception);
throw new MalformedRequestException('Unable to fetch the list of records due to unexpected error');
}
@@ -43,4 +45,4 @@ abstract class AbstractListRecord extends AbstractGetRecord
}
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class DoesNotHaveTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereDoesntHave('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class HasPaymentStatusIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', $value);
});
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\TransactionType;
use Illuminate\Database\Eloquent\Builder;
class HasPurchaseOrderStatusIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('transactions', function($query) use($value) {
return $query->where('transactions.type', TransactionType::PURCHASE_ORDER)->where('transactions.status', $value);
});
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class HasTransactionType implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->has('transactions', function($query) use($value) {
return $query->where('transactions.type', $value);
});
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class WithWallets implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->with('wallets');
}
}
@@ -3,12 +3,15 @@
namespace App\Classes\Modules\Bookings\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Bookings\Services\Convert1688PurchaseOrderToProductList;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
@@ -21,6 +24,9 @@ class CreatePurchaseOrderFor1688OrderProcessor
/** @var CreatePurchaseOrderTransactionProcessor */
private $createPurchaseOrderTransactionProcessor;
/** @var Convert1688PurchaseOrderToProductList */
private $convert1688PurchaseOrderToProductList;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
@@ -28,31 +34,38 @@ class CreatePurchaseOrderFor1688OrderProcessor
private $createInvoiceTransactionProcessor;
/**
* CreatePurchaseOrderFor1688OrderProcessor constructor.
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
* @param Convert1688PurchaseOrderToProductList $convert1688PurchaseOrderToProductList
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
*/
public function __construct(GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, UpdatesTransactionStatus $updatesTransactionStatus, CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor)
public function __construct(GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, Convert1688PurchaseOrderToProductList $convert1688PurchaseOrderToProductList, UpdatesTransactionStatus $updatesTransactionStatus, CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor)
{
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
$this->convert1688PurchaseOrderToProductList = $convert1688PurchaseOrderToProductList;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor;
}
public function execute(Booking $booking){
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
$products = [
[
'description' => 'please refer to the attachment below',
'quantity' => 1,
'stockCode' => '',
'unit_price' => $booking->fix_amount
]
];
$documents = $booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get();
$products = [];
foreach($documents as $document) {
foreach ($document->files as $file) {
try {
$products = $this->convert1688PurchaseOrderToProductList->execute($file);
} catch (MalformedRequestException $exception) {
continue;
}
}
}
if(empty($products)) return false;
$total = collect($products)->sum(function($product){
return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price']));
@@ -65,9 +78,11 @@ class CreatePurchaseOrderFor1688OrderProcessor
$purchaseOrder = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
$this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED);
if($purchaseOrder->amount === $booking->fix_amount){
$this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED);
$this->createInvoiceTransactionProcessor->execute($booking);
}
$this->createInvoiceTransactionProcessor->execute($booking);
}
}
}
@@ -0,0 +1,91 @@
<?php
namespace App\Classes\Modules\Bookings\Services;
use App\Classes\Exceptions\MalformedRequestException;
use App\Models\File;
use Exception;
use Illuminate\Support\Facades\Storage;
class Convert1688PurchaseOrderToProductList
{
/**
* @param File $file
* @return array
* @throws MalformedRequestException
*/
public function execute(File $file): array
{
$parser = new \Smalot\PdfParser\Parser();
$productList = [];
$shipping = 0;
$discount = 0;
try {
$pdf = $parser->parseFile(Storage::disk('documents')->path($file->file->file_info->original->file));
} catch (Exception $exception) {
throw new MalformedRequestException('Invalid file format.');
}
$text = $pdf->getText();
if(str_contains($text, '订单详情单')) throw new MalformedRequestException('Can\'t process non english documents');
$tables = explode('Amount (yuan)', $text);
$footer = end($tables);
$footer = preg_split('(Shipping|运费)', $footer);
if(array_key_exists(1, $footer)){
$footer = preg_split('/[\t\n]/', $footer[1]);
$shipping = (float) filter_var( $footer[0], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
$discount = array_filter($footer, function($var) { return preg_match("/(Discount|优惠)/", $var); });
$discount = (float) filter_var(reset($discount), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
}
array_shift($tables);
foreach ($tables as $table){
$products = preg_split('/(yuan\/|yuan \/|元\/|元 \/)/', str_replace("\r\n","",$table));
array_pop($products);
foreach ($products as $product){
$product = preg_split('/[\t]/',$product);
$adjuster = (count($product) - 7);
$descriptionIndex = 3 + $adjuster;
$quantity = (int) str_replace("\n","",$product[$descriptionIndex + 2]);
$unitPrice = (float) str_replace("\n","",$product[$descriptionIndex + 3]);
$productList[] = [
'stockCode' => '',
'description' => str_replace("\n","",$product[$descriptionIndex]),
'quantity' => $quantity,
'unit_price' => $unitPrice,
'total' => (float) str_replace("\n","",$product[$descriptionIndex + 3])
];
}
}
if($shipping > 0) {
$productList[] = [
'stockCode' => '',
'description' => 'Shipping Fee',
'quantity' => 1,
'unit_price' => $shipping,
'total' => $shipping
];
}
if($discount > 0) {
$productList[] = [
'stockCode' => '',
'description' => 'Discount',
'quantity' => 1,
'unit_price' => $discount * -1,
'total' => $discount * -1
];
}
return $productList;
}
}
@@ -52,10 +52,10 @@ class FetchCompanyLogic extends AbstractControllerLogic
{
$this->canFetchCompany->passes();
$query = $this->fetchesCompany->execute(['id' => $request->route('id'), 'with_bookings' => true]);
$query = $this->fetchesCompany->execute(['id' => $request->route('id'), 'with_bookings' => true, 'with_wallets' => true]);
return $this->resourceResponse(new CompanyResource($query));
}
}
}
@@ -80,9 +80,9 @@ class ExportsTransactions implements FromQuery, WithHeadingRow, WithMapping, Sho
$transactionTypes[$transaction->type],
$transaction->issuerCompany->name,
$transaction->reciver,
$transaction->currency_id === 1 ? 'MYR' : 'RMB',
$transaction->currency->short_code,
$transaction->amount,
$transaction->original_currency_id === 1 ? 'MYR' : 'RMB',
$transaction->original_currency->short_code,
$transaction->original_amount,
$transaction->currency_rate,
$transaction->tax,
@@ -90,7 +90,7 @@ class ExportsTransactions implements FromQuery, WithHeadingRow, WithMapping, Sho
$transactionStatus[$transaction->status],
\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel($transaction->created_at),
\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel($transaction->updated_at),
$marking
// $marking
];
}
}
}
@@ -100,7 +100,7 @@ class CreateProformaInvoiceTransactionProcessor
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Booking $booking)
public function execute(Booking $booking)
{
$po_order_transaction = $booking->transactions()
@@ -129,14 +129,26 @@ class CreateProformaInvoiceTransactionProcessor
$billNumber = $this->generatesTransactionBillNumber->execute('PROFORMA-');
$payable_amount = $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->sum('amount');
$payable_amount = $booking->transactions()->payments()->where(function($query){
return $query->where(function($query){
return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString());
})->orWhere(function($query){
return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
});
})->sum('amount');
$booking_amount = $booking->fix_amount;
$transaction = $booking->transactions()
->where('type', TransactionType::PAYMENT)
->first();
$booking_currency_average_rate = $booking_amount / $booking->transactions()->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::SUSPENDED])->payments()->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
$booking_currency_average_rate = $booking_amount / $booking->transactions()->payments()->where(function($query){
return $query->where(function($query){
return $query->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString());
})->orWhere(function($query){
return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
});
})->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total');
$total_service_charge = $booking->transactions()
->where('type', TransactionType::PAYMENT)
@@ -86,4 +86,4 @@ class GeneratesGroupTransactionsPurchaseOrder
}
}
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ class BookingResource extends JsonResource
->whereDate('expires_on', '>=', Carbon::now())
->get()
),
'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '<', Carbon::now())->get()),
'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()),
'payment_history' => TransactionResource::collection($this->transactions()->where(function($query){
$query->where(function($query){
$query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]);
+1 -1
View File
@@ -61,7 +61,7 @@ class CompanyResource extends JsonResource
],
'segments' => SegmentResource::collection($this->segments),
'services' => (new FetchesCompanyServices())->getServices($this->servicesConfigurations()),
'wallet' => new WalletResource($this->wallets()->first()),
'wallet' => $this->whenLoaded('wallets', new WalletResource($this->wallets()->with('transactions')->first()), new WalletResource($this->wallets()->first())),
'created_at' => $this->created_at->format('d-m-Y'),
$this->mergeWhen($this->business_type === BusinessType::CURRENCY_VENDOR, [
'currencies' => $segment ? CurrencyResource::collection(Currency::whereIn('id', $segment->detail->currencies)->get()) : [],
+2 -2
View File
@@ -21,8 +21,8 @@ class WalletResource extends JsonResource
'currency_id' => $this->currency_id,
'amount' => (double) $this->amount,
'company_id' => (int) $this->owner->id,
'transactions' => WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()),
'top_up_records' => WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get())
'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []),
'top_up_records' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get()), []),
];
}
}