diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index fd26e02..066d756 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -4,8 +4,9 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Auth; -use App\Models\{Account,Payment,PaymentItem,Service,SiteDetail}; +use App\Models\{Account,Charge,InvoiceItem,Payment,PaymentItem,Service,SiteDetail}; class AdminController extends Controller { @@ -14,6 +15,54 @@ class AdminController extends Controller return View('a.service',['o'=>$o]); } + public function charge_addedit(Request $request,Charge $o) + { + if ($request->post()) { + $request->validate([ + 'account_id' => 'required|exists:accounts,id', + 'charge_date' => 'required|date', + 'service_id' => 'required|exists:ab_service,id', + 'quantity' => 'required|numeric|not_in:0', + 'amount' => 'required|numeric|min:0.01', + 'sweep_type' => 'required|numeric|in:'.implode(',',array_keys(Charge::sweep)), + 'type' => 'required|numeric|in:'.implode(',',array_keys(InvoiceItem::type)), + 'taxable' => 'nullable|boolean', + 'description' => 'nullable|string|max:128', + ]); + + if (! $o->exists) { + $o->site_id = config('SITE')->site_id; + $o->user_id = Auth::id(); + $o->active = TRUE; + } + + $o->forceFill($request->only(['account_id','charge_date','service_id','quantity','amount','sweep_type','type','taxable','description'])); + $o->save(); + + return redirect()->back() + ->with('success','Charge recorded: '.$o->id); + } + + return view('a.charge.addedit') + ->with('o',$o); + } + + public function charge_pending_account(Request $request,Account $o) + { + return view('a.charge.widgets.pending') + ->with('list',$o->charges->where('active',TRUE)->where('processed',NULL)->except($request->exclude)); + } + + /** + * List unprocessed charges + * + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + */ + public function charge_unprocessed() + { + return view('a.charge.unprocessed'); + } + /** * Record payments on an account. * @@ -64,13 +113,13 @@ class AdminController extends Controller $oo->invoice_id = $id; } - $oo->alloc_amt = $amount; + $oo->alloc_amt = ($oo->invoice->due >= 0) && ($oo->invoice->due-$amount >= 0) ? $amount : 0; $oo->site_id = config('SITE')->site_id; $o->items()->save($oo); } return redirect()->back() - ->with('success','Payment recorded'); + ->with('success','Payment recorded: '.$o->id); } return view('a.payment.addedit') diff --git a/app/Http/Controllers/ResellerServicesController.php b/app/Http/Controllers/ResellerServicesController.php index 7e523f0..bbedf5d 100644 --- a/app/Http/Controllers/ResellerServicesController.php +++ b/app/Http/Controllers/ResellerServicesController.php @@ -2,7 +2,10 @@ namespace App\Http\Controllers; -use Auth; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; + +use App\Models\Account; class ResellerServicesController extends Controller { @@ -21,6 +24,14 @@ class ResellerServicesController extends Controller return ['data'=>Auth::user()->all_clients()->values()]; } + public function services(Request $request,Account $o) + { + return $o->services + ->filter(function($item) use ($request) { + return $item->active || ($item->id == $request->include); + }); + } + public function service_inactive() { return ['data'=>Auth::user()->all_client_service_inactive()->values()]; diff --git a/app/Models/Account.php b/app/Models/Account.php index 22b2226..465b930 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -16,6 +16,7 @@ use App\Traits\NextKey; * Attributes for accounts: * + lid: : Local ID for account * + sid: : System ID for account + * + name: : Account Name * * @package App\Models */ @@ -48,6 +49,11 @@ class Account extends Model implements IDs /* RELATIONS */ + public function charges() + { + return $this->hasMany(Charge::class); + } + /** * Return the country the user belongs to */ diff --git a/app/Models/Charge.php b/app/Models/Charge.php index 5d997d7..8ea4929 100644 --- a/app/Models/Charge.php +++ b/app/Models/Charge.php @@ -3,15 +3,67 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; +/** + * CLEANUP NOTES: + * + Charge Date should not be null + * + Attributes should be a collection array + * + type should not be null + */ class Charge extends Model { - protected $table = 'ab_charge'; - protected $dates = ['date_charge']; + const CREATED_AT = 'date_orig'; + const UPDATED_AT = 'date_last'; + + protected $dates = ['charge_date']; public $dateFormat = 'U'; + public const sweep = [ + // 0 => 'Daily', + // 1 => 'Weekly', + // 2 => 'Monthly', + // 3 => 'Quarterly', + // 4 => 'Semi-Annually', + // 5 => 'Annually', + 6 => 'Service Rebill', + ]; + + /* RELATIONS */ + + public function account() + { + return $this->belongsTo(Account::class); + } + + public function service() + { + return $this->belongsTo(Service::class); + } + + /* SCOPES */ + + public function scopeUnprocessed($query) + { + return $query + ->where('active',TRUE) + ->whereNotNull('charge_date') + ->whereNotNull('type') + ->where(function($q) { + return $q->where('processed',FALSE) + ->orWhereNull('processed'); + }); + } + + /* ATTRIBUTES */ + public function getNameAttribute() { return sprintf('%s %s',$this->description,$this->getAttribute('attributes') ? join('|',unserialize($this->getAttribute('attributes'))) : ''); } + + public function getTypeAttribute($value) + { + return Arr::get(InvoiceItem::type,$value); + } } \ No newline at end of file diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index bd6d40c..bd6f302 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -37,6 +37,22 @@ class InvoiceItem extends Model // Array of items that can be updated with PushNew protected $pushable = ['taxes']; + public const type = [ + 1 => 'Hardware', // * + 2 => 'Service Relocation Fee', // * Must have corresponding SERVICE_ID + 3 => 'Service Change', // * Must have corresponding SERVICE_ID + 4 => 'Service Connection', // * Must have corresponding SERVICE_ID + 6 => 'Service Cancellation', // * Must have corresponding SERVICE_ID + 7 => 'Extra Product/Service Charge', // * Service Billing in advance, Must have corresponding SERVICE_ID + 8 => 'Product Addition', // * Additional Product Customisation, Must have corresponding SERVICE_ID + 120 => 'Credit/Debit Transfer', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL : INVOICE_ID is NOT NULL + 123 => 'Shipping', + 124 => 'Late Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, + 125 => 'Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, MODULE_REF = CHECKOUT NAME + 126 => 'Other', // * MODEL_ID should be a module + 127 => 'Rounding', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL + ]; + /* RELATIONS */ public function invoice() @@ -98,6 +114,7 @@ class InvoiceItem extends Model public function getItemTypeNameAttribute() { + // @todo use self::type $types = [ 1=>'Hardware', // * 2=>'Service Relocation Fee', // * Must have corresponding SERVICE_ID @@ -118,8 +135,11 @@ class InvoiceItem extends Model { // * Line Charge Topic on Invoice. case 0: - return sprintf('%s [%s]','Product/Service', - $this->date_start == $this->date_stop ? $this->date_start->format('Y-m-d') : sprintf('%s -> %s',$this->date_start->format('Y-m-d'),$this->date_stop->format('Y-m-d'))); + if ($this->date_start) + return sprintf('%s [%s]','Product/Service', + (($this->date_start == $this->date_stop) || (! $this->date_stop)) ? $this->date_start->format('Y-m-d') : sprintf('%s -> %s',$this->date_start->format('Y-m-d'),$this->date_stop->format('Y-m-d'))); + else + return 'Product/Service'; // * Excess Service Item, of item 0, must have corresponding SERVICE_ID case 5: diff --git a/app/Models/Payment.php b/app/Models/Payment.php index b4c92c8..ad3eba2 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -3,11 +3,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; - -use App\Interfaces\IDs; use Illuminate\Support\Facades\DB; use Leenooks\Traits\ScopeActive; -use App\Traits\{NextKey,PushNew}; + +use App\Interfaces\IDs; +use App\Traits\PushNew; /** * Class Payment @@ -74,7 +74,6 @@ class Payment extends Model implements IDs public function scopeUnapplied($query) { - //DB::enableQueryLog(); return $query ->select(['payments.id','payment_date','account_id','checkout_id','total_amt',DB::raw("SUM(alloc_amt) as allocated")]) ->leftJoin('payment_items',['payment_items.payment_id'=>'payments.id']) diff --git a/app/Models/PaymentItem.php b/app/Models/PaymentItem.php index 894f9a8..2c25d18 100644 --- a/app/Models/PaymentItem.php +++ b/app/Models/PaymentItem.php @@ -17,6 +17,11 @@ class PaymentItem extends Model /* RELATIONS */ + public function invoice() + { + return $this->belongsTo(Invoice::class); + } + public function payment() { return $this->belongsTo(Payment::class); } diff --git a/database/migrations/2021_09_30_132207_rework_charges.php b/database/migrations/2021_09_30_132207_rework_charges.php new file mode 100644 index 0000000..9942bc8 --- /dev/null +++ b/database/migrations/2021_09_30_132207_rework_charges.php @@ -0,0 +1,49 @@ +dropForeign('fk_chg_acc'); + $table->dropForeign('fk_chg_pdt'); + $table->dropForeign('fk_chg_svc'); + $table->dropIndex('fk_chg_acc_idx'); + $table->dropIndex('fk_chg_svc_idx'); + $table->dropIndex('fk_chg_pdt_idx'); + $table->dropPrimary(['id','account_id','site_id']); + }); + + DB::statement('ALTER TABLE ab_charge RENAME TO charges'); + DB::statement('ALTER TABLE charges RENAME COLUMN date_charge TO charge_date'); + DB::statement('ALTER TABLE charges MODIFY COLUMN id INT auto_increment'); + + Schema::table('charges', function (Blueprint $table) { + $table->unique(['id','account_id','site_id']); + $table->foreign(['account_id','site_id'])->references(['id','site_id'])->on('accounts'); + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('ab_service'); + $table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('ab_product'); + $table->integer('user_id')->unsigned()->nullable(); + $table->foreign(['user_id','site_id'])->references(['id','site_id'])->on('users'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + abort(500,'cant go back'); + } +} diff --git a/resources/views/theme/backend/adminlte/a/charge/addedit.blade.php b/resources/views/theme/backend/adminlte/a/charge/addedit.blade.php new file mode 100644 index 0000000..b940340 --- /dev/null +++ b/resources/views/theme/backend/adminlte/a/charge/addedit.blade.php @@ -0,0 +1,345 @@ +@extends('adminlte::layouts.app') + +@section('htmlheader_title') + Charge {{ $o->id ? '#'. $o->id : '' }} +@endsection +@section('page_title') + Charge +@endsection + +@section('contentheader_title') + Record Charge +@endsection +@section('contentheader_description') +@endsection + +@section('main-content') +
ID | +Date Created | +Date Charge | +Account | +Service | +Description | +Total | +
---|---|---|---|---|---|---|
{{ $o->id }} | +{{ $o->charge_date->format('Y-m-d') }} | +{{ $o->date_orig->format('Y-m-d') }} | +{{ $o->account->name }} | +{{ $o->service->name_short }} | +{{ $o->description }} | +{{ number_format($o->quantity*$o->amount,2) }} | +
ID | +Date Created | +Date Charge | +Service | +Type | +Description | +Total | +
---|---|---|---|---|---|---|
{{ $co->id }} | +{{ $co->date_orig->format('Y-m-d') }} | +{{ $co->charge_date->format('Y-m-d') }} | +{{ $co->service->sid }} | +{{ $co->type }} | +{{ $co->description }} | +{{ number_format($co->quantity*$co->amount,2) }} | +
Payments
- + +Charges
+ -Unprocessed
+ +Payments
+ + + +