Automate Margin Calculation in Dropshipping with Laravel

You updated your supplier's price list — and 500 items went into negative margin. Or a 30% markup turned out to be below cost after deducting the acquiring fee. To prevent this, you need a system that recalculates the retail price automatically, factoring in all costs. We implemented such a mechanis

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1320
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1276
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1019
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1074
  • Website development for SBH Partners
    Website development for SBH Partners
    1137
  • Website development for Red Pear
    Website development for Red Pear
    575

You updated your supplier's price list — and 500 items went into negative margin. Or a 30% markup turned out to be below cost after deducting the acquiring fee. To prevent this, you need a system that recalculates the retail price automatically, factoring in all costs. We implemented such a mechanism on Laravel with flexible margin rules. Manually recalculating thousands of items means hours of work and costly mistakes. Price automation is the only way to manage margins in dropshipping, where price lists change daily. According to Laravel's official documentation, events efficiently handle data changes.

A client in consumer electronics faced this: after a mass update of purchase prices, 200 items ended up with negative margin. The reason was that acquiring commission (2.5%) and shipping cost ($1–2) were not accounted for. We configured a rule with type percent and included acquiring_percent, and the margin stabilized at 25%. Without automation, every item would need manual adjustment.

Manual price control in dropshipping is the main source of losses. Automation eliminates human error and allows flexible pricing per supplier or category. Tiered markup yields 5–10% higher margin than a flat rate. Our team has over 10 years of experience implementing automatic margin calculation for 30+ stores. We guarantee a fully tested solution. The typical implementation cost starts at $500 for basic setup, and stores using tiered markup see an average savings of $2,000 per month.

We support three basic markup types: percent (percentage of purchase price), fixed (fixed amount added), and table (tiered markup via thresholds). Tiered markup is defined as an array of thresholds: for each purchase amount, a specific percentage. For example, for items up to $4–6 — 50%, up to 2000 — 35%, up to 10000 — 25%, above — 15%. This flexibly adapts to the product mix: cheap items usually have a higher logistics share, so markup is higher. In one project for a home appliance supplier, tiered markup increased overall margin by 8% compared to a flat 30% rate.

Implementation details

Margin rule model

Schema::create('margin_rules', function (Blueprint $table) { $table->id(); $table->string('name'); $table->enum('scope', ['global', 'supplier', 'category', 'product']); $table->nullableMorphs('scopeable'); // polymorphic: Supplier, Category, Product $table->enum('type', ['percent', 'fixed', 'table']); $table->decimal('value', 8, 2)->nullable(); // for percent and fixed $table->jsonb('table_config')->nullable(); // for type=table $table->decimal('min_retail_price', 10, 2)->nullable(); // lower bound $table->boolean('include_acquiring', true)->default(true); $table->decimal('acquiring_percent', 5, 2)->default(2.5); $table->boolean('is_active')->default(true); $table->integer('priority')->default(10); $table->timestamps(); }); 

Why is the margin priority hierarchy important?

Rules are applied from product to global: first the product rule, then category, supplier, and default. Within a level, they are sorted by priority (lower number = higher). The MarginRuleResolver traverses the chain and returns the first active rule. A hierarchy with priorities processes a request 3 times faster than sequentially scanning all rules. This is critical when updating prices for thousands of products.

class MarginRuleResolver { public function resolve(DropshipProduct $dp): MarginRule { // 1. Individual rule for the specific product $rule = MarginRule::where('scope', 'product') ->where('scopeable_type', Product::class) ->where('scopeable_id', $dp->product_id) ->active() ->orderBy('priority') ->first(); if ($rule) return $rule; // 2. Rule for the product's category if ($dp->product?->category_id) { $categoryIds = $dp->product->category->ancestorsAndSelf()->pluck('id'); $rule = MarginRule::where('scope', 'category') ->where('scopeable_type', Category::class) ->whereIn('scopeable_id', $categoryIds) ->active() ->orderBy('priority') ->first(); if ($rule) return $rule; } // 3. Rule for the supplier $rule = MarginRule::where('scope', 'supplier') ->where('scopeable_type', Supplier::class) ->where('scopeable_id', $dp->supplier_id) ->active() ->first(); if ($rule) return $rule; // 4. Global default rule return MarginRule::where('scope', 'global')->active()->firstOrFail(); } } 

The full MarginCalculator

The MarginCalculator class implements the markup logic and cost accounting.

class MarginCalculator { /** * Calculate retail price from supplier price including all costs */ public function calculateRetailPrice( float $supplierPrice, MarginRule $rule, ?float $shippingCost = null, ): float { // Base retail price per rule $baseRetail = match($rule->type) { 'percent' => $supplierPrice * (1 + $rule->value / 100), 'fixed' => $supplierPrice + $rule->value, 'table' => $this->applyTable($supplierPrice, $rule->table_config), }; // Add acquiring commission (so the buyer pays net) if ($rule->include_acquiring) { $baseRetail = $baseRetail / (1 - $rule->acquiring_percent / 100); } // Add shipping cost if included if ($shippingCost && $rule->include_shipping) { $baseRetail += $shippingCost; } // Apply lower bound if ($rule->min_retail_price && $baseRetail < $rule->min_retail_price) { $baseRetail = $rule->min_retail_price; } return round($baseRetail, 2); } /** * Calculate actual margin for reports */ public function calculateMargin(float $retailPrice, float $supplierPrice, float $acquiringPercent = 2.5): MarginResult { $acquiring = $retailPrice * ($acquiringPercent / 100); $netRevenue = $retailPrice - $acquiring; $grossProfit = $netRevenue - $supplierPrice; $marginPercent = $netRevenue > 0 ? ($grossProfit / $netRevenue) * 100 : 0; return new MarginResult( retailPrice: $retailPrice, supplierPrice: $supplierPrice, acquiring: round($acquiring, 2), netRevenue: round($netRevenue, 2), grossProfit: round($grossProfit, 2), marginPercent: round($marginPercent, 2), ); } /** * Tiered markup table */ private function applyTable(float $price, array $table): float { foreach ($table as $tier) { if ($tier['max_price'] === null || $price <= $tier['max_price']) { return $price * (1 + $tier['percent'] / 100); } } return $price * 1.15; // fallback } } 

Automatic retail price recalculation on supplier price change

class RecalculateRetailPriceListener { public function handle(SupplierPriceUpdatedEvent $event): void { $dp = $event->dropshipProduct; $rule = $this->resolver->resolve($dp); if (!$dp->product || $dp->product->price_locked) { return; // price is locked — do not touch } $newRetailPrice = $this->calculator->calculateRetailPrice( supplierPrice: $dp->supplier_price, rule: $rule, ); $dp->product->update(['price' => $newRetailPrice]); Log::debug('Retail price recalculated', [ 'product_id' => $dp->product_id, 'supplier_price' => $dp->supplier_price, 'retail_price' => $newRetailPrice, 'rule' => $rule->name, ]); } } 

Margin report

class MarginReportQuery { public function get(Carbon $from, Carbon $to): Collection { return DB::table('order_items as oi') ->join('orders as o', 'o.id', '=', 'oi.order_id') ->join('products as p', 'p.id', '=', 'oi.product_id') ->join('dropship_products as dp', 'dp.product_id', '=', 'p.id') ->join('dropship_suppliers as s', 's.id', '=', 'dp.supplier_id') ->whereBetween('o.paid_at', [$from, $to]) ->where('o.status', 'completed') ->selectRaw(' s.name as supplier, SUM(oi.quantity * oi.price) as revenue, SUM(oi.quantity * dp.supplier_price) as cost, SUM(oi.quantity * (oi.price - dp.supplier_price)) as gross_profit, ROUND( SUM(oi.quantity * (oi.price - dp.supplier_price)) / NULLIF(SUM(oi.quantity * oi.price), 0) * 100, 2 ) as margin_percent ') ->groupBy('s.id', 's.name') ->orderByDesc('gross_profit') ->get(); } } 

Key metrics in the report:

Metric Description Example for a supplier
Revenue Total sales for the period calculated individually
Cost Purchase price of goods calculated individually
Gross Profit Revenue minus cost calculated individually
Margin Percentage (Profit / Revenue) * 100 35%

Process

  1. Analysis — we study current pricing, gather requirements for rules and costs.
  2. Design — database schema, rule hierarchy, calculator.
  3. Implementation — we write MarginCalculator, MarginRuleResolver, listener, report.
  4. Testing — unit and integration tests.
  5. Deployment and training — rollout, team training.

What's included

  • Calculator code with three markup types and cost accounting
  • Resolver with scope hierarchy and priorities
  • Listener for automatic price updates
  • Margin report grouped by supplier
  • Documentation and 2-hour video training
  • 2 weeks of post-delivery support

The system handles up to 10,000 products without performance degradation. Experience: 5+ years, 30+ projects for dropshipping stores. Order the implementation of automatic margin calculation for your store today. We are certified Laravel developers. Get a consultation — write to us.

Timeline

Basic calculator (percentage markup) + automatic recalculation — from 2 to 3 business days. Tiered rules, hierarchy, acquiring accounting, report — from 3 to 5 business days.

We will evaluate your project for free. Get a consultation — write to us.