diff --git a/app/Classes/General/Eloquent/Filters/DoesNotHaveSegments.php b/app/Classes/General/Eloquent/Filters/DoesNotHaveSegments.php
new file mode 100644
index 00000000..88a1ab3d
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/DoesNotHaveSegments.php
@@ -0,0 +1,21 @@
+whereDoesntHave('segments', function ($segment) use ($value) {
+ $segment->whereIn('id', $value);
+ });
+ }
+}
diff --git a/app/Classes/General/Eloquent/Filters/IssuerNot.php b/app/Classes/General/Eloquent/Filters/IssuerNot.php
new file mode 100644
index 00000000..77423b5d
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/IssuerNot.php
@@ -0,0 +1,20 @@
+where('issuer', '!=', $value);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/SegmentsIn.php b/app/Classes/General/Eloquent/Filters/SegmentsIn.php
new file mode 100644
index 00000000..3f756810
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/SegmentsIn.php
@@ -0,0 +1,21 @@
+whereHas('segments', function ($segment) use ($value) {
+ $segment->whereIn('id', $value);
+ });
+ }
+}
diff --git a/app/Classes/General/Eloquent/Filters/WithOutTransactions.php b/app/Classes/General/Eloquent/Filters/WithOutTransactions.php
new file mode 100644
index 00000000..3b551f65
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/WithOutTransactions.php
@@ -0,0 +1,20 @@
+whereDoesntHave('transactions');
+ }
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/WithTotalPayments.php b/app/Classes/General/Eloquent/Filters/WithTotalPayments.php
new file mode 100644
index 00000000..d93e55e2
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/WithTotalPayments.php
@@ -0,0 +1,25 @@
+leftJoin('bookings', 'companies.id', '=', 'bookings.company_id')->rightJoin('transactions', function ($join) {
+ $join->on('bookings.id', '=', 'transactions.booking_id')->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ })->addSelect(['companies.*', DB::raw('SUM(transactions.amount) as total_payments')])->groupBy(['companies.id']);
+ }
+}
\ No newline at end of file
diff --git a/app/Classes/General/Eloquent/Filters/WithoutConfirmedPayments.php b/app/Classes/General/Eloquent/Filters/WithoutConfirmedPayments.php
new file mode 100644
index 00000000..e17ed5da
--- /dev/null
+++ b/app/Classes/General/Eloquent/Filters/WithoutConfirmedPayments.php
@@ -0,0 +1,24 @@
+whereDoesntHave('transactions', function($transaction){
+ return $transaction->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
index 528eb618..940d6565 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
@@ -79,7 +79,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
$outstanding = $this->calculatesBookingOutstanding->execute($booking);
- if($conversionObject->getAmount() > $outstanding) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding .'.');
+ if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding .'.');
$configurations = $this->fetchBookingQuotation->execute($booking->company, $conversionObject);
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php
index c20450d8..5885d560 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php
@@ -68,7 +68,7 @@ class FetchBookingPaymentQuotationLogic extends AbstractControllerLogic
$conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $request->input('amount'))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')]);
$outstanding = $this->calculatesBookingOutstanding->execute($booking);
- if($conversionObject->getAmount() > $outstanding) throw new MalformedRequestException('Your payment must not be greater than '.$booking->fixedCurrency->short_code.' '. number_format((float)$outstanding, 2, '.', ','));
+ if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '.$booking->fixedCurrency->short_code.' '. number_format((float)$outstanding, 2, '.', ','));
return $this->response(['data' => $this->generatesBookingQuotation->execute(
$this->fetchBookingQuotation->execute($booking->company, $conversionObject),
diff --git a/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php b/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php
index 7c3eacd6..6c5003c8 100644
--- a/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php
+++ b/app/Classes/Modules/Transactions/Services/CreatesWalletTransaction.php
@@ -32,7 +32,6 @@ class CreatesWalletTransaction extends AbstractUpdateRelationshipRecord
$model->service_charge = $object->getServiceCharge();
$model->expires_on = $object->getExpiresOn();
$model->status = $object->getStatus();
- $model->booking_id = 0;
return $this->handler($wallet->transactions(), $model);
diff --git a/app/Classes/ValueObjects/Constants/RoleTypes.php b/app/Classes/ValueObjects/Constants/RoleTypes.php
index 3027bcb1..ec5fe961 100644
--- a/app/Classes/ValueObjects/Constants/RoleTypes.php
+++ b/app/Classes/ValueObjects/Constants/RoleTypes.php
@@ -16,4 +16,12 @@ final class RoleTypes
public const USER = 3;
+ public const CURRENCY_SUPPLIER = 4;
+
+ public const MONEY_MULE = 5;
+
+ public const ORIGIN_ACCOUNT_ADMIN = 6;
+
+ public const DESTINATION_ACCOUNT_ADMIN = 7;
+
}
\ No newline at end of file
diff --git a/app/Http/Controllers/Wallets/WithdrawWalletController.php b/app/Http/Controllers/Wallets/WithdrawWalletController.php
index 0d125aa7..7c7b944a 100644
--- a/app/Http/Controllers/Wallets/WithdrawWalletController.php
+++ b/app/Http/Controllers/Wallets/WithdrawWalletController.php
@@ -2,14 +2,14 @@
namespace App\Http\Controllers\Wallets;
-use App\Classes\Modules\Wallets\ControllersLogic\CreateWalletLogic;
+use App\Classes\Modules\Wallets\ControllersLogic\WithdrawWalletLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class WithdrawWalletController
{
- public function withdraw(Request $request, CreateWalletLogic $logic): JsonResponse {
+ public function withdraw(Request $request, WithdrawWalletLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
diff --git a/app/Http/Resources/CompanyResource.php b/app/Http/Resources/CompanyResource.php
index 655cfc98..a35c7082 100644
--- a/app/Http/Resources/CompanyResource.php
+++ b/app/Http/Resources/CompanyResource.php
@@ -9,6 +9,7 @@ use App\Classes\ValueObjects\Constants\BusinessType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Classes\ValueObjects\Constants\SegmentConstants;
+use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Currency;
use App\Models\SegmentConstant;
use Illuminate\Http\Resources\Json\JsonResource;
@@ -24,6 +25,7 @@ class CompanyResource extends JsonResource
*/
public function toArray($request)
{
+ $lastPayment = $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->orderBy('id', 'DESC')->first();
return [
'id' => $this->id,
'name' => $this->name,
@@ -33,9 +35,11 @@ class CompanyResource extends JsonResource
'status' => (int) $this->status,
'contact' => new ContactResource ($this->when($this->has('contacts'), $this->contacts->first())),
'address' => new AddressResource($this->when($this->has('addresses'), $this->addresses->where('billing', true)->first())),
- 'employee' => new UserResource(Auth::user()->type === RoleTypes::USER ? $this->employees()->where('email', '=', Auth::user()->email)->first() : $this->employees()->where('users.status', '=', ApprovalStatus::APPROVED)->orderBy('id', 'DESC')->first()),
+ 'employee' => new UserResource(Auth::user()->type === RoleTypes::USER ? $this->employees()->where('email', '=', Auth::user()->email)->first() : $this->employees()->orderBy('id', 'DESC')->first()),
'identification' => new DocumentResource($this->documents->whereIn('document_type', DocumentType::IDENTIFICATION_DOCUMENTS)->first()),
'bookings' => $this->whenLoaded('bookings', $this->bookings()->orderBy('id', 'DESC')->get(), []),
+ 'total_payments' => (float) $this->transactions()->where('transactions.type', TransactionType::PAYMENT)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount'),
+ 'last_payment' => $lastPayment ? $lastPayment->created_at->diffForHumans() : 'No Payments',
'personal_banks' => BankResource::collection($this->banks->where('type', BankAccountType::PERSONAL)),
'recipient_banks' => [
'accounts' => BankResource::collection($this->banks->where('type', BankAccountType::EXTERNAL)),
@@ -46,7 +50,8 @@ class CompanyResource extends JsonResource
'currencies' => $this->when($this->business_type === BusinessType::CURRENCY_VENDOR, function(){
$segment = SegmentConstant::where('reference', SegmentConstants::SUPPLIER_CURRENCIES)->where('detail->id', $this->id)->first();
return $segment ? CurrencyResource::collection(Currency::whereIn('id', $segment->detail->currencies)->get()) : [];
- })
+ }),
+ 'created_at' => $this->created_at->format('d-m-Y')
];
diff --git a/app/Http/Resources/TransactionResource.php b/app/Http/Resources/TransactionResource.php
index fc0dff73..1793d191 100644
--- a/app/Http/Resources/TransactionResource.php
+++ b/app/Http/Resources/TransactionResource.php
@@ -21,6 +21,7 @@ class TransactionResource extends JsonResource
'booking' => new BookingResource($this->booking),
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
+ 'recipient_bank_account' => new BankResource($this->when((int) $this->type === TransactionType::BILL,$this->booking->bank)),
'amount' => (double) $this->amount,
'original_amount' => (double) $this->original_amount,
'currency' => new CurrencyResource($this->currency),
diff --git a/app/Models/Company.php b/app/Models/Company.php
index eba6677f..ab94c46e 100644
--- a/app/Models/Company.php
+++ b/app/Models/Company.php
@@ -12,6 +12,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
+use Staudenmeir\EloquentHasManyDeep\HasManyDeep;
+use Staudenmeir\EloquentHasManyDeep\HasRelationships;
+
/**
* Class Company
@@ -27,11 +30,12 @@ use Illuminate\Support\Collection;
*/
class Company extends AbstractModel implements Documentable
{
+ use HasRelationships;
use SoftDeletes;
protected $table = 'companies';
- protected $dates = ['deleted_at'];
+ protected $dates = ['deleted_at', 'created_at'];
/**
@@ -90,6 +94,14 @@ class Company extends AbstractModel implements Documentable
return $this->HasMany(Booking::class, 'company_id');
}
+ /**
+ * @return hasManyDeep
+ */
+ public function transactions(): hasManyDeep
+ {
+ return $this->hasManyDeep(Transaction::class, [Booking::class], ['company_id', 'booking_id'], ['id', 'id']);
+ }
+
/**
* @return MorphMany
*/
diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php
index cad64361..e10e1781 100644
--- a/app/Models/Transaction.php
+++ b/app/Models/Transaction.php
@@ -9,6 +9,8 @@ use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
+use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
@@ -46,6 +48,14 @@ class Transaction extends AbstractModel implements Documentable
return $this->BelongsTo(Wallet::class, 'owner_id', 'id');
}
+ /**
+ * @return BelongsTo
+ */
+ public function recipientBankAccount(): BelongsTo
+ {
+ return $this->BelongsTo(Bank::class);
+ }
+
/**
* @return MorphMany
*/
diff --git a/composer.json b/composer.json
index 7715f0ca..3323db18 100644
--- a/composer.json
+++ b/composer.json
@@ -11,6 +11,7 @@
"php": "^7.2.5",
"ext-fileinfo": "*",
"ext-json": "^1.6",
+ "ext-zip": "*",
"barryvdh/laravel-dompdf": "^0.9.0",
"carlos-meneses/laravel-mpdf": "^2.1",
"doctrine/dbal": "2.*",
@@ -24,6 +25,7 @@
"rinvex/countries": "^6.1",
"spatie/laravel-activitylog": "^3.14",
"spatie/laravel-permission": "^3.17",
+ "staudenmeir/eloquent-has-many-deep": "^1.7",
"tymon/jwt-auth": "^1.0"
},
"require-dev": {
diff --git a/config/database.php b/config/database.php
index b42d9b30..aeabec6f 100644
--- a/config/database.php
+++ b/config/database.php
@@ -56,7 +56,7 @@ return [
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
- 'strict' => true,
+ 'strict' => false,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
diff --git a/resources/assets/vue/components/banks/elements/BankInComponent.vue b/resources/assets/vue/components/banks/elements/BankInComponent.vue
new file mode 100644
index 00000000..ff42850a
--- /dev/null
+++ b/resources/assets/vue/components/banks/elements/BankInComponent.vue
@@ -0,0 +1,36 @@
+
+