Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eec7add
feat: add GL assignment rules engine and export batch migrations
TLemmAI Apr 13, 2026
8285afb
feat: add GL assignment models, update Account with hierarchy, add Ha…
TLemmAI Apr 13, 2026
5404c62
feat: add GL auto-assignment service with rules evaluation engine
TLemmAI Apr 13, 2026
d0b60cd
feat: add GL export service with CSV, QuickBooks IIF, and JSON format…
TLemmAI Apr 13, 2026
23fb4a2
feat: add carrier invoice, line items, and audit rules table migrations
TLemmAI Apr 13, 2026
fffb176
feat: add GL assignment controllers, resources, routes, and service r…
TLemmAI Apr 13, 2026
efae309
feat: add CarrierInvoice, CarrierInvoiceItem, and CarrierInvoiceAudit…
TLemmAI Apr 13, 2026
75e9081
feat: add carrier invoice audit service with discrepancy detection an…
TLemmAI Apr 13, 2026
d37420c
feat: add CarrierInvoiceReceived and CarrierInvoiceApproved events
TLemmAI Apr 13, 2026
9544347
feat: add carrier invoice controller, resources, routes, and GL event…
TLemmAI Apr 13, 2026
0a2f7e8
feat(BUILD-06): add service agreements, charge templates, and client …
TLemmAI Apr 13, 2026
a1dabd3
feat(BUILD-06): add ServiceAgreement, ChargeTemplate, ClientInvoice m…
TLemmAI Apr 13, 2026
ddd0ec6
feat(BUILD-06): add ClientInvoiceGeneratorService, BatchInvoiceServic…
TLemmAI Apr 13, 2026
2d5d26a
feat(BUILD-06): add controllers, resources, routes for service agreem…
TLemmAI Apr 13, 2026
1a7a5ff
feat(BUILD-07): add gainshare engine with cost benchmarks, rules, cal…
TLemmAI Apr 13, 2026
09db43e
fix(BUILD-07): rate unit conversion, loss tracking, deduplication guard
TLemmAI Apr 13, 2026
8109080
feat(BUILD-07): add benchmark_source to GainshareRule with rate_contr…
TLemmAI Apr 13, 2026
f48f9f3
feat(BUILD-09): add pay files with safe lifecycle (draft→generated→se…
TLemmAI Apr 14, 2026
97ec25d
feat(BUILD-07): activate rate_contract benchmark path via BUILD-10 ra…
TLemmAI Apr 14, 2026
b1c2337
feat(BUILD-11): add batch-approve endpoint to CarrierInvoiceController
TLemmAI Apr 14, 2026
963bef4
feat(multi-tenant): apply ScopedToCompanyContext to CarrierInvoice, S…
TLemmAI Apr 14, 2026
f149738
feat(settings): wire PayFileGeneratorService payment_method to Compan…
TLemmAI Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::table('ledger_accounts', function (Blueprint $table) {
$table->char('parent_account_uuid', 36)->nullable()->after('status');
$table->boolean('is_active')->default(true)->after('parent_account_uuid');

$table->foreign('parent_account_uuid')
->references('uuid')
->on('ledger_accounts')
->nullOnDelete();

$table->index('parent_account_uuid');
});
}

public function down()
{
Schema::table('ledger_accounts', function (Blueprint $table) {
$table->dropForeign(['parent_account_uuid']);
$table->dropIndex(['parent_account_uuid']);
$table->dropColumn(['parent_account_uuid', 'is_active']);
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('gl_assignment_rules', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->string('name');
$table->integer('priority')->default(0);
$table->string('match_type', 20)->default('all');
$table->char('gl_account_uuid', 36);
$table->string('target', 50);
$table->boolean('is_active')->default(true);
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
$table->foreign('gl_account_uuid')->references('uuid')->on('ledger_accounts');
});
}

public function down()
{
Schema::dropIfExists('gl_assignment_rules');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('gl_assignment_conditions', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->char('gl_assignment_rule_uuid', 36);
$table->string('field', 50);
$table->string('operator', 20);
$table->text('value');
$table->json('meta')->nullable();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('gl_assignment_rule_uuid')
->references('uuid')
->on('gl_assignment_rules')
->cascadeOnDelete();
});
}

public function down()
{
Schema::dropIfExists('gl_assignment_conditions');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('gl_assignments', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->char('gl_account_uuid', 36);
$table->char('gl_assignment_rule_uuid', 36)->nullable();
$table->string('assignable_type');
$table->char('assignable_uuid', 36);
$table->decimal('amount', 12, 2);
$table->string('assignment_type', 20)->default('auto');
$table->json('meta')->nullable();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
$table->foreign('gl_account_uuid')->references('uuid')->on('ledger_accounts');
$table->foreign('gl_assignment_rule_uuid')->references('uuid')->on('gl_assignment_rules')->nullOnDelete();
$table->index(['assignable_type', 'assignable_uuid']);
});
}

public function down()
{
Schema::dropIfExists('gl_assignments');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('gl_export_batches', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->string('format', 30);
$table->string('status', 20)->default('pending');
$table->date('period_start');
$table->date('period_end');
$table->char('file_uuid', 36)->nullable();
$table->integer('record_count')->default(0);
$table->decimal('total_amount', 14, 2)->default(0);
$table->timestamp('exported_at')->nullable();
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
});
}

public function down()
{
Schema::dropIfExists('gl_export_batches');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('carrier_invoices', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->char('vendor_uuid', 36)->index();
$table->char('order_uuid', 36)->nullable()->index();
$table->char('shipment_uuid', 36)->nullable()->index();
$table->string('invoice_number')->nullable();
$table->string('pro_number')->nullable()->index();
$table->string('bol_number')->nullable()->index();

$table->string('source', 20)->default('manual');
$table->string('status', 20)->default('pending');

$table->decimal('invoiced_amount', 12, 2);
$table->decimal('planned_amount', 12, 2)->nullable();
$table->decimal('approved_amount', 12, 2)->nullable();
$table->decimal('discrepancy_amount', 12, 2)->nullable();
$table->decimal('discrepancy_percent', 5, 2)->nullable();

$table->string('discrepancy_type', 20)->nullable();
$table->string('resolution', 20)->nullable();
$table->text('resolution_notes')->nullable();
$table->char('resolved_by', 36)->nullable();
$table->timestamp('resolved_at')->nullable();

$table->date('invoice_date')->nullable();
$table->date('due_date')->nullable();
$table->timestamp('received_at')->nullable();
$table->date('pickup_date')->nullable();
$table->date('delivery_date')->nullable();

$table->string('currency', 3)->default('USD');
$table->char('file_uuid', 36)->nullable();
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
$table->foreign('vendor_uuid')->references('uuid')->on('vendors');
$table->foreign('resolved_by')->references('uuid')->on('users')->nullOnDelete();
});
}

public function down()
{
Schema::dropIfExists('carrier_invoices');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('carrier_invoice_items', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->char('carrier_invoice_uuid', 36)->index();
$table->string('charge_type', 30);
$table->string('description')->nullable();
$table->string('accessorial_code', 20)->nullable();

$table->decimal('invoiced_amount', 10, 2);
$table->decimal('planned_amount', 10, 2)->nullable();
$table->decimal('approved_amount', 10, 2)->nullable();
$table->decimal('discrepancy_amount', 10, 2)->nullable();

$table->decimal('quantity', 10, 2)->nullable();
$table->decimal('rate', 10, 4)->nullable();
$table->string('rate_type', 20)->nullable();

$table->json('meta')->nullable();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('carrier_invoice_uuid')
->references('uuid')
->on('carrier_invoices')
->cascadeOnDelete();
});
}

public function down()
{
Schema::dropIfExists('carrier_invoice_items');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('carrier_invoice_audit_rules', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->string('name');
$table->string('rule_type', 30);
$table->decimal('tolerance_percent', 5, 2)->nullable();
$table->decimal('tolerance_amount', 10, 2)->nullable();
$table->string('charge_type', 30)->nullable();
$table->boolean('is_active')->default(true);
$table->integer('priority')->default(0);
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
});
}

public function down()
{
Schema::dropIfExists('carrier_invoice_audit_rules');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
public function up() {
Schema::create('service_agreements', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->char('customer_uuid', 36)->index(); // the shipper/client
$table->string('name');
$table->string('status', 20)->default('draft'); // draft, active, expired, cancelled
$table->string('billing_frequency', 20)->default('per_shipment'); // per_shipment, weekly, biweekly, monthly
$table->integer('payment_terms_days')->default(30); // net 30, net 60, etc.
$table->date('effective_date');
$table->date('expiration_date')->nullable();
$table->string('currency', 3)->default('USD');
$table->text('notes')->nullable();
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
});
}
public function down() { Schema::dropIfExists('service_agreements'); }
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
public function up() {
Schema::create('charge_templates', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid', 191)->nullable()->unique();
$table->string('public_id', 191)->nullable()->unique();
$table->uuid('company_uuid')->index();
$table->string('name');
$table->text('description')->nullable();
$table->boolean('is_active')->default(true);
$table->json('meta')->nullable();
$table->softDeletes();
$table->timestamp('created_at')->nullable()->index();
$table->timestamp('updated_at')->nullable();

$table->foreign('company_uuid')->references('uuid')->on('companies');
});
}
public function down() { Schema::dropIfExists('charge_templates'); }
};
Loading