Skip to main content

Implementation Plan: Enable FAF on Rental Orders

Status: Ready for Implementation
Date: April 24, 2026
Reference: ADR-002-FAF-on-Rental-Orders.md
Author: Cascade AI Assistant


Overview

This document provides a phased implementation plan for enabling Fuel Adjustment Factor (FAF) on rental orders. Each phase is designed to be implemented and tested independently.


Phase 1: Backend Repository Layer (Foundation) ✅ IMPLEMENTED

Objective: Implement core FAF calculation logic in the repository layer that all other components will use.

Files to Modify:

  1. app/Repositories/OrderRentalRepository.php

Changes:

1.1 Update createDetail() Method (Lines ~1272-1342)

public static function createDetail(
$detail,
$code,
$type,
$date,
$price = 0,
$qty = 1,
$additionalData = [],
$additionalPrice = 0,
$isFromRunsheetGroup = 1
) {
// ... existing code ...

// Calculate FAF using FuelAdjustmentRepository (fresh from current Partner config)
$fafBaseAmount = $price * $qty;
$faf_total_amount = FuelAdjustmentRepository::calculateFAF($fafBaseAmount);
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

$faf_applied_type = null;
$faf_applied_rate = 0;

if ($faf_total_amount > 0 && $fafConfig) {
$faf_applied_type = $fafConfig->faf_type;
$faf_applied_rate = $fafConfig->faf_value;
}

// Calculate subtotal including FAF
$baseSubtotal = $price * $qty;
$subtotalWithFAF = $baseSubtotal + $faf_total_amount;

$delivery = OrderDetail::create([
// ... existing fields ...
'subtotal' => $subtotalWithFAF, // Subtotal includes FAF

// ADD THESE FAF FIELDS:
'faf_applied_type' => $faf_applied_type,
'faf_applied_rate' => $faf_applied_rate,
'faf_total_amount' => $faf_total_amount,

// ... rest of fields ...
]);

return $delivery;
}

1.2 Update extraOrderDetailTask() Method (Lines ~785-889)

public static function extraOrderDetailTask($data, $order, $request)
{
// ... existing code ...

// Calculate FAF before creating order detail
$fafBaseAmount = $data['final_price'] * $data['quantity'];
$faf_total_amount = FuelAdjustmentRepository::calculateFAF($fafBaseAmount);
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

$baseSubtotal = $data['final_price'] * $data['quantity'];
$subtotalWithFAF = $baseSubtotal + $faf_total_amount;

$newOrderDetail = OrderDetail::query()->create([
// ... existing fields ...
'price' => $data['final_price'],
'quantity' => $data['quantity'],
'subtotal' => $subtotalWithFAF, // Subtotal includes FAF

// ADD FAF FIELDS:
'faf_applied_type' => $faf_total_amount > 0 ? $fafConfig->faf_type : null,
'faf_applied_rate' => $faf_total_amount > 0 ? $fafConfig->faf_value : 0,
'faf_total_amount' => $faf_total_amount,

// ... rest of fields ...
]);

// ... rest of method ...
}

Testing Checklist:

  • Test runsheet generates child order details with FAF
  • Test empty task includes FAF in subtotal
  • Test delivery task includes FAF in subtotal
  • Test extra empty invoice includes FAF in subtotal
  • Verify FAF calculation: $price * $qty base amount
  • Verify subtotal = base + FAF

Note: This createDetail() method is also called during rerun runsheet when FAF config changes. The fresh FAF calculation ensures new config is applied to future order details.


Phase 2: Backend Controllers (Manual Child Detail Creation) ✅ IMPLEMENTED

Objective: Add FAF to manual child order detail creation routes.

Files to Modify:

  1. app/Http/Controllers/Admin/OrderController.php

Changes:

2.1 Update storePickupDate() Method (Lines ~4243-4293)

public function storePickupDate(Request $request, $id)
{
$order = Order::findOrFail($id);
$orderDetail = OrderDetail::findOrFail($request->change_over['order_detail_id']);

$newOrderDetail = DB::transaction(function () use ($request, $order, $orderDetail) {
// Calculate FAF before creating order detail
$fafBaseAmount = $request->change_over['price'] * $request->change_over['quantity'];
$faf_total_amount = FuelAdjustmentRepository::calculateFAF($fafBaseAmount);
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

$baseSubtotal = $request->change_over['price'] * $request->change_over['quantity'];
$subtotalWithFAF = $baseSubtotal + $faf_total_amount;

$newOrderDetail = OrderDetail::create([
// ... existing fields ...
'subtotal' => $subtotalWithFAF, // Subtotal includes FAF

// ADD FAF FIELDS:
'faf_applied_type' => $faf_total_amount > 0 ? $fafConfig->faf_type : null,
'faf_applied_rate' => $faf_total_amount > 0 ? $fafConfig->faf_value : 0,
'faf_total_amount' => $faf_total_amount,
]);

$openStatus = Status::where([
'namespace' => 'task',
'name' => 'Open',
])->first();

TaskRepository::create('C', 'Pickup', $request->change_over['change_over_date'], $openStatus, $newOrderDetail, 0, 1);

return $newOrderDetail;
});

return [
'data' => $newOrderDetail,
'message' => 'date has ben created successfully',
'status' => 1
];
}

Testing Checklist:

  • Test "Create Pickup Bin" from rental order page includes FAF
  • Verify FAF fields in response data
  • Verify subtotal includes FAF

Phase 3: Backend Controller FAF Updates ✅ IMPLEMENTED

Objective: Add FAF calculation and storage to backend controller methods that currently lack FAF support.

Backend FAF Status:

  • ChangeOverController@store - Has FAF (lines 95-96, 125-126, 171-173)
  • OrderController@storePickupDate - Has FAF (Phase 2)
  • FrontBinController@postExtraInvoice - Has FAF via OrderRentalRepository::extraOrderDetailTask (Phase 1)
  • RentalBinsController@storeRentalBinOrder - Missing FAF
  • RentalBinsController@storeChangeOver - Missing FAF
  • RentalBinsController@storeEmptyReturn - Missing FAF

3.1 Update RentalBinsController@storeRentalBinOrder (Line 1752)

Add FAF calculation before creating OrderDetail:

// Calculate FAF based on total price (price × quantity)
$totalPrice = $request->rental_order['price'] * $request->rental_order['quantity'];
$fafData = FuelAdjustmentRepository::calculateFAF($totalPrice, $order->customer_id);
$fafAmount = $fafData['faf_total_amount'];

// Include FAF in subtotal
$subtotal = $request->rental_order['grandTotal'] + $fafAmount;

Add FAF fields to OrderDetail create:

'faf_applied_type' => $fafData['faf_applied_type'],
'faf_applied_rate' => $fafData['faf_applied_rate'],
'faf_total_amount' => $fafAmount,

3.2 Update RentalBinsController@storeChangeOver (Line 695)

Add FAF calculation before creating OrderDetail:

// Calculate FAF based on total price (price × quantity)
$totalPrice = $change_over['price'] * $change_over['quantity'];
$fafData = FuelAdjustmentRepository::calculateFAF($totalPrice, $order->customer_id);
$fafAmount = $fafData['faf_total_amount'];

// Include FAF in subtotal
$subtotal = $change_over['grandTotal'] + $fafAmount;

Add FAF fields to OrderDetail create:

'faf_applied_type' => $fafData['faf_applied_type'],
'faf_applied_rate' => $fafData['faf_applied_rate'],
'faf_total_amount' => $fafAmount,

3.3 Update RentalBinsController@prepareEmptyReturn (Line 1136)

Add FAF calculation before returning data:

// Calculate FAF based on total price (price × quantity)
$totalPrice = $orderDetail['price'] * $orderDetail['quantity'];
$fafData = FuelAdjustmentRepository::calculateFAF($totalPrice, $order->customer_id);
$fafAmount = $fafData['faf_total_amount'];

// Include FAF in grandtotal
$grandtotal = @$orderDetail['grandTotal'] + $weightExtraPrice + $fafAmount;

Add FAF fields to return array:

'faf_applied_type' => $fafData['faf_applied_type'],
'faf_applied_rate' => $fafData['faf_applied_rate'],
'faf_total_amount' => $fafAmount,

Phase 4: Frontend Vue Components (FAF Display) ✅ IMPLEMENTED

Objective: Add FAF calculation and display to frontend components for transparency.

Files to Modify:

  1. resources/js/components/AdminChangeOver.vue - Change Over form (non-rental) - Remove rental exclusion only
  2. resources/js/components/rental-bins/RentalBin.vue - Create Bin Rental Fee Order
  3. resources/js/components/rental-bins/changeOverRentalBins.vue - Create Change Over (rental)
  4. resources/js/components/rental-bins/EmptyReturnRentalBins.vue - Create Empty and Return
  5. resources/js/components/rental-bins/PickupDate.vue - Create Pickup Bin - Already has FAF (Phase 2)
  6. resources/js/components/front-bins/ExtraEmpty.vue - Create Empty (frontlift/wheelie bins) - Already has FAF (Phase 1)

Files NOT Modified:

  • AddServicePricing.vue - No FAF display in service pricing forms (admin aware from Partner config)
  • EditServicePricing.vue - No FAF display in service pricing forms

Changes:

4.1 Update AdminChangeOver.vue (Lines ~1942-1965)

Remove rental exclusion:

// BEFORE (around line 1942):
if (this.order.is_rental) {
this.fafAmount = 0;
this.fafDisplayText = '';
return;
}

// AFTER:
// Remove this block - rental orders should now include FAF

Fix FAF calculation to include quantity:

// BEFORE (around line 1957):
const basePrice = parseFloat(this.orderDetail.price) || 0;

// AFTER:
const totalPrice = (parseFloat(this.orderDetail.price) || 0) * (this.orderDetail.quantity || 1);

Update FAF calculation to use totalPrice:

// BEFORE (around line 1960):
this.fafAmount = Math.round(basePrice * (this.faf_config.faf_value / 100) * 100) / 100;

// AFTER:
this.fafAmount = Math.round(totalPrice * (this.faf_config.faf_value / 100) * 100) / 100;

4.2 Update rental-bins/RentalBin.vue - Create Bin Rental Fee Order

Add FAF calculation method (reference AdminChangeOver.vue lines 1935-1960):

calculateFAF() {
if (!this.faf_config || !this.faf_config.has_faf) {
this.fafAmount = 0;
this.fafDisplayText = '';
return;
}

// Calculate total price (base price × quantity)
const totalPrice = (parseFloat(this.orderDetail.price) || 0) * (this.orderDetail.quantity || 1);

if (this.faf_config.faf_type === 'percentage') {
this.fafAmount = Math.round(totalPrice * (this.faf_config.faf_value / 100) * 100) / 100;
this.fafDisplayText = this.faf_config.faf_value + '%';
} else {
this.fafAmount = parseFloat(this.faf_config.faf_value) || 0;
this.fafDisplayText = '$' + this.fafAmount.toFixed(2);
}
}

Display FAF in order summary section.

4.3 Update rental-bins/changeOverRentalBins.vue - Create Change Over (Rental)

Add FAF calculation method (reference AdminChangeOver.vue lines 1935-1960).

Display FAF in order summary section.

4.4 Update rental-bins/EmptyReturnRentalBins.vue - Create Empty and Return

Add FAF calculation method (reference AdminChangeOver.vue lines 1935-1960).

Display FAF in order summary section.

4.5 rental-bins/PickupDate.vue - NO CHANGES NEEDED

Status: Already has FAF display (Phase 2).

4.6 front-bins/ExtraEmpty.vue - NO CHANGES NEEDED

Status: Already has FAF display (Phase 1).

4.7 AddServicePricing.vue - NO CHANGES NEEDED

Status: No FAF display in Service Pricing forms.

Reason: Admin is already aware of FAF enable/disable/type from Partner config page. FAF will be displayed on child order details and invoices.

4.8 EditServicePricing.vue - NO CHANGES NEEDED

Status: No FAF display in Service Pricing forms.

4.9 Pass faf_config from Controllers to Blade Views

Objective: Ensure faf_config is passed from controllers to Blade views so Vue components can receive it as a prop.

Controller Methods to Update:

4.9.1 RentalBinsController - createRentalBinOrder (line 1751-1768)

File: app/Http/Controllers/Admin/RentalBins/RentalBinsController.php

Add faf_config retrieval:

// Get FAF configuration from Partner model
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

return view('admin.rental-bins.rental-bin', compact('order', 'services', 'fafConfig'));

4.9.2 RentalBinsController - createChangeOver (line 666-693)

File: app/Http/Controllers/Admin/RentalBins/RentalBinsController.php

Add faf_config retrieval:

// Get FAF configuration from Partner model
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

return view('admin.rental-bins.change-over', compact(
'order',
'services',
'binWeights',
'drivers',
'wasteTypes',
'fafConfig'
));

4.9.3 RentalBinsController - createEmptyReturn (line 1041-1087)

File: app/Http/Controllers/Admin/RentalBins/RentalBinsController.php

Add faf_config retrieval:

// Get FAF configuration from Partner model
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

return view('admin.rental-bins.empty-return', compact(
'order',
'orderDetails',
'binWeights',
'taskDetail',
'coupon',
'services',
'stations',
'drivers',
'binSizes',
'fafConfig'
));

4.9.4 RentalBinsController - editEmptyReturn (line 1090-1143)

File: app/Http/Controllers/Admin/RentalBins/RentalBinsController.php

Add faf_config retrieval:

// Get FAF configuration from Partner model
$fafConfig = FuelAdjustmentRepository::getFAFConfig();

return view('admin.rental-bins.edit-empty-return', compact(
'order',
'orderDetails',
'binWeights',
'taskDetail',
'coupon',
'services',
'stations',
'orderDetail',
'binWeights',
'drivers',
'binSizes',
'fafConfig'
));

Blade Views to Update:

4.9.5 admin/rental-bins/rental-bin.blade.php

File: resources/views/admin/rental-bins/rental-bin.blade.php

Add faf_config prop to rental-bin component:

<rental-bin
code="EBNZ-{{ strtoupper(Str::random(10)) }}"
order_from="admin"
url_to="{{ URL::to('/admin') }}"
date="{{ date('j F Y') }}"
:order="{{ json_encode($order, JSON_NUMERIC_CHECK) }}"
:details="{{ json_encode($order->details, JSON_NUMERIC_CHECK) }}"
:customer_="{{ json_encode($order->customer, JSON_NUMERIC_CHECK) }}"
price="0"
stripekey="{{ config('services.stripe.public_key') }}"
:pos_services="{{ json_encode($services, JSON_NUMERIC_CHECK)}}"
:faf_config="{{ json_encode($fafConfig) }}"
></rental-bin>

4.9.6 admin/rental-bins/change-over.blade.php

File: resources/views/admin/rental-bins/change-over.blade.php

Add faf_config prop to change-over-rental-bins component:

<change-over-rental-bins
code="EBNZ-{{ strtoupper(Str::random(10)) }}"
order_from="admin"
url_to="{{ URL::to('/admin') }}"
date="{{ date('j F Y') }}"
:order="{{ json_encode($order, JSON_NUMERIC_CHECK) }}"
:order_detail="{{ (isset($orderDetail))?json_encode($orderDetail, JSON_NUMERIC_CHECK):'null' }}"
:details="{{ json_encode($order->details, JSON_NUMERIC_CHECK) }}"
:customer_="{{ json_encode($order->customer, JSON_NUMERIC_CHECK) }}"
price="{{ json_encode($order->orderPricingModule->change_over_price, JSON_NUMERIC_CHECK) }}"
stripekey="{{ config('services.stripe.public_key') }}"
:pos_services="{{ json_encode($services, JSON_NUMERIC_CHECK) }}"
:bin_informations="{{ json_encode($binWeights, JSON_NUMERIC_CHECK) }}"
:drivers="{{ json_encode($drivers, JSON_NUMERIC_CHECK) }}"
:waste_types="{{ json_encode($wasteTypes, JSON_NUMERIC_CHECK) }}"
:faf_config="{{ json_encode($fafConfig) }}"
></change-over-rental-bins>

4.9.7 admin/rental-bins/empty-return.blade.php

File: resources/views/admin/rental-bins/empty-return.blade.php

Add faf_config prop to empty-return-rental-bins component:

<empty-return-rental-bins
:order_="{{ json_encode($order, JSON_NUMERIC_CHECK) }}"
order_from="admin"
:details="{{ json_encode($order->details, JSON_NUMERIC_CHECK) }}"
code="{{ 'EBNZ-'.strtoupper(Str::random(10)) }}"
date="{{ (\Carbon\Carbon::now())->format('Y-m-d') }}"
stripekey="{{ config('services.stripe.public_key') }}"
:customer_="{{ json_encode($order->customer, JSON_NUMERIC_CHECK) }}"
:pos_services="{{ json_encode($services, JSON_NUMERIC_CHECK)}}"
:stations="{{ json_encode($stations, JSON_NUMERIC_CHECK) }}"
:bin_informations="{{ json_encode($binWeights, JSON_NUMERIC_CHECK) }}"
:drivers="{{ json_encode($drivers, JSON_NUMERIC_CHECK) }}"
:bin_sizes="{{ json_encode($binSizes, JSON_NUMERIC_CHECK) }}"
:faf_config="{{ json_encode($fafConfig) }}"
></empty-return-rental-bins>

4.9.8 admin/rental-bins/edit-empty-return.blade.php

File: resources/views/admin/rental-bins/edit-empty-return.blade.php

Add faf_config prop to empty-return-rental-bins component:

<empty-return-rental-bins
:order_="{{ json_encode($order, JSON_NUMERIC_CHECK) }}"
order_from="admin"
:details="{{ json_encode($order->details, JSON_NUMERIC_CHECK) }}"
code="{{ 'EBNZ-'.strtoupper(Str::random(10)) }}"
date="{{ (\Carbon\Carbon::now())->format('Y-m-d') }}"
stripekey="{{ config('services.stripe.public_key') }}"
:customer_="{{ json_encode($order->customer, JSON_NUMERIC_CHECK) }}"
:pos_services="{{ json_encode($services, JSON_NUMERIC_CHECK) }}"
:stations="{{ json_encode($stations, JSON_NUMERIC_CHECK) }}"
:bin_informations="{{ json_encode($binWeights, JSON_NUMERIC_CHECK) }}"
:order_detail="{{ json_encode($orderDetail, JSON_NUMERIC_CHECK) }}"
:drivers="{{ json_encode($drivers, JSON_NUMERIC_CHECK) }}"
:bin_sizes="{{ json_encode($binSizes, JSON_NUMERIC_CHECK) }}"
:faf_config="{{ json_encode($fafConfig) }}"
></empty-return-rental-bins>

Note: AdminChangeOver.vue already receives faf_config from ChangeOverController.php (admin/change-over/update.blade.php).

Testing Checklist:

  • Test FAF displays in AdminChangeOver.vue (after removing rental exclusion)
  • Test FAF displays in rental-bins/RentalBin.vue
  • Test FAF displays in rental-bins/changeOverRentalBins.vue
  • Test FAF displays in rental-bins/EmptyReturnRentalBins.vue
  • Verify FAF displays in rental-bins/PickupDate.vue (already working)
  • Verify FAF displays in front-bins/ExtraEmpty.vue (already working)
  • Verify NO FAF display in AddServicePricing.vue (as intended)
  • Verify NO FAF display in EditServicePricing.vue (as intended)
  • Verify FAF calculation matches backend
  • Verify grand total includes FAF
  • Verify faf_config is passed from controllers to Blade views
  • Verify faf_config prop is received by Vue components

Phase 5: Testing & Validation ⏳ PENDING

Objective: Comprehensive testing of all FAF scenarios including rerun after config change.

Note on Rerun Runsheet: When FAF config is updated, the system will trigger RerunRunsheetCalendar command starting from tomorrow's date. This will:

  1. Delete existing future child order details (from tomorrow onward)
  2. Regenerate them using the new FAF config via OrderRentalRepository::createDetail()
  3. Existing order details (today and past) remain unchanged

Test Scenarios:

4.1 Runsheet Flow Tests

  • Generate runsheet for rental order with FAF enabled
  • Verify child order details have FAF snapshot
  • Verify subtotal includes FAF
  • Generate runsheet with FAF disabled
  • Verify FAF = 0 on child order details

4.2 Manual Creation Tests

  • Create Pickup Bin manually - verify FAF
  • Create Extra Empty Invoice - verify FAF
  • Create Empty & Return - verify FAF (via runsheet)
  • Create Change Over - verify FAF (via runsheet)

4.3 Rerun Tests (FAF Config Change)

  • Update FAF config (enable/disable or change value)
  • Trigger rerun runsheet from tomorrow's date
  • Verify new FAF values applied to future order details only
  • Verify existing order details (today/past) unchanged
  • Verify existing invoices unchanged
  • Verify active rental contracts get new FAF for future runsheets

4.4 Invoice Tests

  • Generate invoice for rental order
  • Verify FAF line item appears
  • Verify FAF amount correct
  • Test PDF invoice
  • Test email invoice

4.5 Category Tests

  • Test frontlift bin rental
  • Test wheelie bin rental
  • Test trash bag rental
  • Test skip bin rental

4.6 Edge Cases

  • Test FAF percentage type
  • Test FAF fixed amount type
  • Test FAF = 0 (disabled)
  • Test quantity > 1
  • Test price = 0 (pickup)

Phase 6: FAF Config Change Rerun ⏳ PENDING

Objective: Automatically rerun all active rental runsheets when FAF config changes, so future child order details use the new FAF rates.

Flow:

  1. Admin saves FAF config → updateFAFConfig() detects change via wasChanged()
  2. Dispatch RerunRunsheetForFAFChangeJob
  3. Job finds all active rental RunsheetGroups → dispatches ScheduleGroupJob per group
  4. ScheduleGroupJob calls RunsheetRentalRepository::changeTaskGroups() which handles deletion of future open tasks/details and regeneration

Reference: Same pattern as RunsheetGroupController::update() (lines 364-368) where ProgressHelper::setProgress() is called before dispatch(new ScheduleGroupJob()).

Files to Modify:

  1. app/Http/Controllers/Admin/GeneralWasteBinHireController.php — add change detection + dispatch
  2. app/Jobs/RerunRunsheetForFAFChangeJob.phpnew file

Changes:

5.1 Add Change Detection in updateFAFConfig() (Lines ~220-263)

public function updateFAFConfig(Request $request, $supplier_id)
{
$partner = Partner::where('is_default', 1)->first();
// ... existing validation and auth checks ...

$partner->update([
'has_faf' => $validated['has_faf'] ?? false,
'faf_type' => ($validated['has_faf'] ?? false) ? $validated['faf_type'] : null,
'faf_value' => ($validated['has_faf'] ?? false) ? $validated['faf_value'] : null,
'faf_label' => $validated['faf_label'] ?? 'Fuel Adjustment Factor',
]);

// NEW: Trigger rerun if FAF config changed
if ($partner->wasChanged(['has_faf', 'faf_type', 'faf_value'])) {
dispatch(new RerunRunsheetForFAFChangeJob());
}

return response()->json([
'success' => true,
'message' => 'FAF configuration updated successfully'
]);
}

5.2 Create RerunRunsheetForFAFChangeJob

New File: app/Jobs/RerunRunsheetForFAFChangeJob.php

<?php

namespace App\Jobs;

use App\RunsheetGroup;
use App\Helpers\ProgressHelper;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class RerunRunsheetForFAFChangeJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public function __construct()
{
}

public function handle()
{
$runsheetGroups = RunsheetGroup::where('is_active', 1)
->whereIn('category', ['frontlift bin', 'wheelie bin', 'trash bag', 'skip bin', 'rental bin'])
->get();

foreach ($runsheetGroups as $runsheetGroup) {
ProgressHelper::setProgress($runsheetGroup->id, 0);
dispatch(new ScheduleGroupJob($runsheetGroup));
}
}
}

How it works:

  • ScheduleGroupJob receives a RunsheetGroup and calls RunsheetRentalRepository::changeTaskGroups()
  • changeTaskGroups() deletes future open tasks + child order details, then regenerates them via getNextdateSchedule() or generateScheduleSession()
  • Regenerated child order details will pick up the new FAF config via OrderRentalRepository::createDetail() (Phase 1)

Testing Checklist:

  • Test FAF config change triggers RerunRunsheetForFAFChangeJob
  • Test wasChanged() returns false when FAF config unchanged
  • Test all active rental RunsheetGroups are processed
  • Test ProgressHelper::setProgress() is called before each ScheduleGroupJob
  • Test future child order details have updated FAF values
  • Test existing order details (today/past) are NOT affected
  • Test changeTaskGroups() handles deletion + regeneration correctly

Phase 6: Cleanup (Optional) ⏳ PENDING

Objective: Remove dead code and finalize.

Files to Modify:

  1. app/Repositories/FuelAdjustmentRepository.php

Changes:

6.1 Remove Rental Check (Optional)

// In applyFAFToOrderDetail() method (lines ~63-66)
// Remove or comment out:
// if ($order->is_rental) {
// return;
// }

Note: This method is dead code but cleaning it up prevents confusion.


Summary Table

PhaseStatusComponentsTest Focus
1✅ DoneRepository (createDetail, extraOrderDetailTask)Runsheet flow, FAF calculation, subtotal
2✅ DoneController (storePickupDate)Manual Pickup creation
3✅ DoneBackend Controllers (3 methods: storeRentalBinOrder, storeChangeOver, prepareEmptyReturn)FAF calculation and storage in backend
4✅ DoneVue (4 components: AdminChangeOver, RentalBin, changeOverRentalBins, EmptyReturnRentalBins)FAF display in frontend
5⏳ PendingAllEnd-to-end testing, edge cases
6⏳ PendingFAF Config Change Rerun (RerunRunsheetForFAFChangeJobScheduleGroupJob)Change detection, rerun trigger, updated FAF on future details
7⏳ PendingRepository cleanupCode cleanup

Notes:

  • Phase 3 adds backend FAF support to 3 controller methods that were missing it
  • Phase 4 adds frontend FAF display to 4 Vue components (PickupDate and ExtraEmpty already have FAF from Phases 1-2)
  • AddServicePricing.vue and EditServicePricing.vue do NOT show FAF (admin aware from Partner config)
  • When FAF config changes, RerunRunsheetForFAFChangeJob dispatches ScheduleGroupJob per active RunsheetGroup — changeTaskGroups() handles deletion + regeneration
  • wasChanged() is used to detect actual FAF config changes (no manual comparison needed)

End of Implementation Plan