code for statement import invoice mapping

This commit is contained in:
Steve Ng
2023-10-06 10:59:36 +08:00
parent ddc1df0d6e
commit d9d3c48e6d
10 changed files with 392 additions and 31 deletions
@@ -0,0 +1,78 @@
<?php
namespace App\Classes\Modules\Exports\Services;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use App\Models\TransactionMappingLog;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
{
use Exportable;
private $dateTime;
private $count;
private $counter = 1;
public function __construct(Request $request)
{
$this->dateTime = $request->input('date').' '.$request->input('time');
$this->count = 0;
}
public function headings(): array
{
return [
'No',
'Doc No',
'Date',
'Debtor Code',
'Debtor Name',
'Shipping Info',
'Net Total',
'Cancelled',
'Mapped Status',
'Mapped Reference No'
];
}
/**
* @return \Illuminate\Support\Collection|mixed
*/
public function query()
{
return TransactionMappingLog::where('imported_date', $this->dateTime);
}
/**
* @param Transaction $transaction
*
* @return array
*/
public function map($transaction): array
{
// dd($transaction);
$this->count += 1;
$data = $transaction->data;
return [
$this->count,
Arr::get($data,'doc_no'),
Arr::get($data,'date'),
Arr::get($data,'debtor_code'),
Arr::get($data,'debtor_name'),
Arr::get($data,'shipping_info'),
Arr::get($data,'net_total'),
Arr::get($data,'cancelled'),
Arr::get($data,'mapped_status'),
Arr::get($data,'mapped_result_reference'),
];
}
}
@@ -15,6 +15,8 @@ use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Maatwebsite\Excel\Excel;
use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds;
use App\Models\TransactionMappingLog;
class ExportCustomersToExcelController
{
@@ -75,4 +77,10 @@ class ExportCustomersToExcelController
ob_end_clean();
return $response;
}
public function importedInvoiceMapped(ExportsImportedInvoiceMappeds $exportsImportedInvoiceMappeds, Request $request) {
$response = $exportsImportedInvoiceMappeds->download('InvoiceMapped.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
ob_end_clean();
return $response;
}
}
@@ -2,33 +2,47 @@
namespace App\Http\Controllers\Imports;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Imports\Services\GenericImport;
use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Segment;
use App\Models\User;
use Carbon\Carbon;
use DateTime;
use Carbon\Carbon;
use App\Models\User;
use App\Models\Company;
use App\Models\Segment;
use App\Models\Transaction;
use Illuminate\Http\Request;
use App\Models\SeasonalSegment;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
use App\Models\TransactionMappingLog;
use App\Classes\ValueObjects\Constants\HttpStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Imports\Services\GenericImport;
use App\Classes\ValueObjects\Response\ApiResponseObject;
use App\Classes\Modules\Accounting\Processors\ChecksBillNumber;
use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment;
use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor;
use App\Models\Company;
use App\Models\SeasonalSegment;
use App\Models\Transaction;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject;
class ImportStatementInvoiceController
{
private $responseTitle;
private $responseMessage;
public function __construct() {
$this->responseTitle = 'Import Invoice Mapping';
$this->responseMessage = 'You have successfully imported invoice mapping';
}
/**
* @param Request $request
* @return array
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function import(Request $request)
public function import(Request $request) : JsonResponse
{
ini_set('memory_limit', '-1');
$importDate = date('Y-m-d H:i:s');
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
$file = json_decode($object->getFiles()[0])->file_info->original->file;
@@ -37,26 +51,37 @@ class ImportStatementInvoiceController
$excelRows = $import->rows;
$excelRows = $excelRows->toArray();
$data = [];
foreach ($excelRows as $row) {
dd($row);
// $row['debtor_code']
// attempt 1 - try map by amount and date
// $transactionDate = $this->changeExcelDate($row['date']);
// $transaction = Transaction::where('original_amount', $row['total'])->whereDate('created_at', $transactionDate)->get();
// if ($transaction) {
// // check company
// // $company = Company::where('debtor', $row['debtor_code'])->first();
// // dd($company);
// // try to verify is it the correct transaction
// }
$row['mapped_result_reference'] = null;
$row['mapped_status'] = 'failed';
$row['date'] = $this->changeExcelDate($row['date']);
// Shipping Info
// TOPUP -> map with transaction.bill_no
if (str_starts_with($row['shipping_info'], 'TOPUP')) {
// find in exchange first, if cannont then find in izyim
// (App()->make(ChecksBillNumber::class))->execute($bill_no, 'exchange');
foreach (['exchange','izyim'] as $system) {
$returnReference = $this->mappingTopUp($row, $system);
if ($returnReference) {
$row['mapped_result_reference'] = $returnReference;
$row['mapped_status'] = 'success';
}
}
} else {
$returnReference = $this->mappingExchange($row);
if ($returnReference) {
$row['mapped_result_reference'] = $returnReference;
$row['mapped_status'] = 'success';
}
}
TransactionMappingLog::create([
'imported_date'=>$importDate,
'data'=>$row,
]);
array_push($data, $row);
// if 5 digits -> exchange booking reference
// find transation
@@ -88,6 +113,51 @@ class ImportStatementInvoiceController
}
return $this->response(['data'=>$data,'importedDate'=>$importDate]);
}
public function response(?array $data = []) : JsonResponse {
return (new ApiResponseObject($this->responseTitle,
$this->responseMessage,
HttpStatus::OK_WITH_MESSAGE, $data))->handler();
}
private function mappingTopUp(Array $row, String $system) {
try {
if ($data = (App()->make(ChecksBillNumber::class))->execute($row['shipping_info'], $system)) {
if ($system == 'izyim' && isset($data['owner_reference'])) return $data['owner_reference'];
if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']);
}
} catch (\Throwable $th) {
return false;
}
}
private function mappingExchange(Array $row) {
$date = $row['date'];
$transactions = Transaction::where('original_amount', $row['net_total'])->whereRaw("DATE(created_at) = '$date'")
->whereHas('receiverCompany', function($q) use($row) {
$q->where('debtor',$row['debtor_code']);
})
->get();
if ($transactions && $transactions->count() == 1) {
foreach ($transactions as $key => $transaction) {
return $this->updateTransactionOwnerReference($transaction, $row['doc_no']);
}
}
return false;
}
public function updateTransactionOwnerReference($transaction, String $docNo) {
$transactionOwner = $transaction->transaction_owner;
if ($transactionOwner) {
$transactionOwner->update(['invoice_reference'=>$docNo]);
return $transactionOwner->owner_reference;
}
return false;
}
public function changeExcelDate($date)
+5
View File
@@ -21,6 +21,11 @@ class StatementTransactionOwner extends Model
'receipt_reference',
'status',
];
public function owner(): morphTo
{
return $this->morphTo();
}
public function transaction(): BelongsTo
{
+19
View File
@@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Staudenmeir\EloquentHasManyDeep\HasTableAlias;
use App\Models\StatementTransactionOwner;
class Transaction extends AbstractModel implements Documentable, Transactionable, Voucherifiable
@@ -53,6 +54,14 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
return $this->MorphOne(Transaction::class, 'owner')->where('type', TransactionType::CREDIT_NOTE);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
*/
public function transaction_owner()
{
return $this->MorphOne(StatementTransactionOwner::class, 'owner','owner_type','owner_id');
}
/**
* @return BelongsTo
*/
@@ -69,6 +78,16 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
return $this->BelongsTo( Company::class, 'issuer', 'id');
}
/**
* Get the user that owns the Transaction
*
* @return BelongsTo
*/
public function receiverCompany(): BelongsTo
{
return $this->belongsTo(Company::class, 'receiver', 'id');
}
/**
* @return BelongsTo
*/
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TransactionMappingLog extends Model
{
protected $fillable = ['imported_by','data','imported_date'];
protected $casts = [
'data' => 'array',
];
public static function boot() {
parent::boot();
static::creating(function ($model) {
$model->imported_by = auth()->user()->id;
});
}
}
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTransactionMappingLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('transaction_mapping_logs', function (Blueprint $table) {
$table->id();
$table->bigInteger('imported_by')->unsigned();
$table->foreign('imported_by')->references('id')->on('users');
$table->dateTime('imported_date')->nullable();
$table->text('data')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('transaction_mapping_logs');
}
}
@@ -0,0 +1,116 @@
<template>
<div class="row h-100 parentContainer">
<div class="col-12" style="min-height: 20px;">
<loading-component style="height: 20px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<h3>Imported Invoice Mapped</h3>
<div class="text-right">
<button class="btn btn-xs btn-outline-success b-rad-none m-r-5" @click="downloadInvoiceMapped">
Download Invoices Mapped
</button>
</div>
</div>
<!-- /.card-header -->
<div class="card-body table-responsive p-0">
<table class="table table-hover">
<thead>
<tr>
<th>No</th>
<th>Doc No</th>
<th>Date</th>
<th>Debtor Code</th>
<th>Debtor Name</th>
<th>Shipping Info</th>
<th>Net Total</th>
<th>Cancelled</th>
<th>Mapped Status</th>
<th>Mapped Reference No</th>
</tr>
</thead>
<tbody v-show="!isLoading">
<tr v-for="(item, index) in $store.getters.getListData(section)">
<td>{{index+1}}</td>
<td>{{item.doc_no }}</td>
<td>{{item.date}}</td>
<td>{{item.debtor_code }}}</td>
<td>{{item.debtor_name}}</td>
<td>{{item.shipping_info}}</td>
<td>{{item.net_total}}</td>
<td>{{item.cancelled}}</td>
<td>{{item.mapped_status}}</td>
<td>{{item.mapped_result_reference}}</td>
</tr>
</tbody>
</table>
</div>
<!-- /.card-body -->
<div class="card-footer">
</div>
</div>
</div>
<div class="col-12">
<pagination-component :section="section" class="mb-5" ref="pagination"></pagination-component>
</div>
</div>
</template>
<script>
export default {
props: {
files: {
required: true
}
},
data() {
return {
section: 'importInvoiceMapping',
isLoading: false,
importedDate: null,
}
},
computed: {
pendingQueue() {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingQueue(inComplete, oldValue){
if(inComplete){
this.importInvoice();
}
},
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
importInvoice(){
this.isLoading = true;
this.parameters = {
files: this.files
};
this.submit(this.route('api.import_invoices.upload'), 'post', this.section, true, false);
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': response.payload.data});
this.importedDate = response.payload.importedDate;
this.isLoading = false;
},
downloadInvoiceMapped() {
var arrDateTime = this.importedDate.split(" ");
window.open(this.route('importedInvoiceMapped.export')+'?date='+arrDateTime[0]+'&time='+arrDateTime[1], '_blank');
},
}
}
</script>
@@ -99,7 +99,7 @@
</div>
</div>
</div>
<div class="row" v-if="stage === 4">
<div class="row parentContainer" v-if="stage === 4">
<div class="col">
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 0">
<div class="col">
@@ -123,7 +123,7 @@
</file-input-component>
</div>
</div>
<div class="btn btn-lg btn-primary m-t-20" @click="importInvoice">Import Invoices</div>
<div class="btn btn-lg btn-primary m-t-20 requestModal" data-type="ModalImportInvoice" @click="importInvoice">Import Invoices</div>
<!-- todo-new: delete later --><br><div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Nest Step</div>
<br>
<div class="row">
@@ -131,6 +131,13 @@
<a href="https://docs.google.com/presentation/d/1XwKcdBCpHQSCQmsgnUHsypcqk5kdc8uZMqkjW9JXiw4/edit?usp=sharing" target="_blank">Learn How to do this step?</a>
</div>
</div>
<div class="row">
<div class="col-12">
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="ModalImportInvoice">
<imported-invoice-mapped-component v-if="mappedTrue" :files="files"></imported-invoice-mapped-component>
</modal-component>
</div>
</div>
</div>
</div>
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 2">
@@ -191,6 +198,7 @@ export default {
files: [],
parameters: {},
section: 'bankTransactionSection',
mappedTrue: false,
}
},
validations: {
@@ -200,10 +208,7 @@ export default {
},
methods: {
importInvoice(){
this.parameters = {
files: this.files
};
this.submit(this.route('api.import_invoices.upload'), 'post', this.section, true, false);
this.mappedTrue = true;
},
importReceipts(){
this.parameters = {
+1
View File
@@ -261,6 +261,7 @@ Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', 'Exp
Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@walletTransactions')->name('walletTransactions.export');
Route::get('/export/booking-transactions', 'Exports\ExportCustomersToExcelController@bookingTransactions')->name('export.transactions.booking');
Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@invoiceTransactions')->name('invoiceTransactions.export');
Route::get('/export/imported-invoice-mapped', 'Exports\ExportCustomersToExcelController@importedInvoiceMapped')->name('importedInvoiceMapped.export');
Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) {
$bookings = Booking::where(function($query){