Skip to content

Commit c2a5a8d

Browse files
committed
Add tests for weight-based shipping pricing tiers and unit conversions
1 parent 961dd3b commit c2a5a8d

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

tests/shipping/Unit/Drivers/ShippingMethods/ShipByTest.php

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
use Illuminate\Foundation\Testing\RefreshDatabase;
44
use Illuminate\Support\Facades\Config;
55
use Lunar\DataTypes\ShippingOption;
6+
use Lunar\Models\Cart;
67
use Lunar\Models\Currency;
8+
use Lunar\Models\Price;
9+
use Lunar\Models\ProductVariant;
710
use Lunar\Models\TaxClass;
811
use Lunar\Shipping\DataTransferObjects\ShippingOptionRequest;
912
use Lunar\Shipping\Drivers\ShippingMethods\ShipBy;
@@ -406,3 +409,175 @@
406409
expect($shippingOption)->toBeInstanceOf(ShippingOption::class);
407410
expect($shippingOption->price->value)->toEqual(800);
408411
});
412+
413+
test('pricing manager resolves correct tier for weight-based shipping using raw kg min_quantity', function () {
414+
$currency = Currency::factory()->create(['default' => true]);
415+
TaxClass::factory()->create(['default' => true]);
416+
417+
$shippingZone = ShippingZone::factory()->create(['type' => 'countries']);
418+
419+
$shippingMethod = ShippingMethod::factory()->create([
420+
'driver' => 'ship-by',
421+
'data' => ['charge_by' => 'weight'],
422+
]);
423+
424+
$shippingRate = ShippingRate::factory()->create([
425+
'shipping_method_id' => $shippingMethod->id,
426+
'shipping_zone_id' => $shippingZone->id,
427+
]);
428+
429+
$shippingRate->prices()->createMany([
430+
['price' => 1000, 'min_quantity' => 1, 'currency_id' => $currency->id],
431+
['price' => 600, 'min_quantity' => 5, 'currency_id' => $currency->id],
432+
['price' => 200, 'min_quantity' => 10, 'currency_id' => $currency->id],
433+
]);
434+
435+
$makeWeightCart = function (float $weightKg) use ($currency): Cart {
436+
$variant = ProductVariant::factory()->create([
437+
'weight_value' => $weightKg,
438+
'weight_unit' => 'kg',
439+
]);
440+
$variant->stock = 100;
441+
442+
Price::factory()->create([
443+
'price' => 500,
444+
'min_quantity' => 1,
445+
'currency_id' => $currency->id,
446+
'priceable_type' => $variant->getMorphClass(),
447+
'priceable_id' => $variant->id,
448+
]);
449+
450+
$cart = Cart::factory()->create(['currency_id' => $currency->id]);
451+
$cart->lines()->create([
452+
'purchasable_type' => $variant->getMorphClass(),
453+
'purchasable_id' => $variant->id,
454+
'quantity' => 1,
455+
]);
456+
457+
return $cart->calculate();
458+
};
459+
460+
$option = (new ShipBy)->resolve(new ShippingOptionRequest(
461+
shippingRate: $shippingRate,
462+
cart: $makeWeightCart(3.0),
463+
));
464+
expect($option)->toBeInstanceOf(ShippingOption::class)
465+
->and($option->price->value)->toEqual(1000);
466+
467+
$option = (new ShipBy)->resolve(new ShippingOptionRequest(
468+
shippingRate: $shippingRate,
469+
cart: $makeWeightCart(5.0),
470+
));
471+
expect($option)->toBeInstanceOf(ShippingOption::class)
472+
->and($option->price->value)->toEqual(600);
473+
474+
$option = (new ShipBy)->resolve(new ShippingOptionRequest(
475+
shippingRate: $shippingRate,
476+
cart: $makeWeightCart(10.0),
477+
));
478+
expect($option)->toBeInstanceOf(ShippingOption::class)
479+
->and($option->price->value)->toEqual(200);
480+
});
481+
482+
test('weight in grams is converted to kg when evaluating weight-based shipping breakpoints', function () {
483+
$currency = Currency::factory()->create(['default' => true]);
484+
TaxClass::factory()->create(['default' => true]);
485+
486+
$shippingZone = ShippingZone::factory()->create(['type' => 'countries']);
487+
488+
$shippingMethod = ShippingMethod::factory()->create([
489+
'driver' => 'ship-by',
490+
'data' => ['charge_by' => 'weight'],
491+
]);
492+
493+
$shippingRate = ShippingRate::factory()->create([
494+
'shipping_method_id' => $shippingMethod->id,
495+
'shipping_zone_id' => $shippingZone->id,
496+
]);
497+
498+
$shippingRate->prices()->createMany([
499+
['price' => 1000, 'min_quantity' => 1, 'currency_id' => $currency->id],
500+
['price' => 500, 'min_quantity' => 5, 'currency_id' => $currency->id],
501+
]);
502+
503+
$variant = ProductVariant::factory()->create([
504+
'weight_value' => 5000.0,
505+
'weight_unit' => 'g',
506+
]);
507+
$variant->stock = 100;
508+
509+
Price::factory()->create([
510+
'price' => 500,
511+
'min_quantity' => 1,
512+
'currency_id' => $currency->id,
513+
'priceable_type' => $variant->getMorphClass(),
514+
'priceable_id' => $variant->id,
515+
]);
516+
517+
$cart = Cart::factory()->create(['currency_id' => $currency->id]);
518+
$cart->lines()->create([
519+
'purchasable_type' => $variant->getMorphClass(),
520+
'purchasable_id' => $variant->id,
521+
'quantity' => 1,
522+
]);
523+
$cart = $cart->calculate();
524+
525+
$option = (new ShipBy)->resolve(new ShippingOptionRequest(
526+
shippingRate: $shippingRate,
527+
cart: $cart,
528+
));
529+
530+
expect($option)->toBeInstanceOf(ShippingOption::class)
531+
->and($option->price->value)->toEqual(500);
532+
});
533+
534+
test('total cart weight across multiple lines with different units is summed in kg for tier matching', function () {
535+
$currency = Currency::factory()->create(['default' => true]);
536+
TaxClass::factory()->create(['default' => true]);
537+
538+
$shippingZone = ShippingZone::factory()->create(['type' => 'countries']);
539+
540+
$shippingMethod = ShippingMethod::factory()->create([
541+
'driver' => 'ship-by',
542+
'data' => ['charge_by' => 'weight'],
543+
]);
544+
545+
$shippingRate = ShippingRate::factory()->create([
546+
'shipping_method_id' => $shippingMethod->id,
547+
'shipping_zone_id' => $shippingZone->id,
548+
]);
549+
550+
$shippingRate->prices()->createMany([
551+
['price' => 1000, 'min_quantity' => 1, 'currency_id' => $currency->id],
552+
['price' => 400, 'min_quantity' => 5, 'currency_id' => $currency->id],
553+
]);
554+
555+
$variantKg = ProductVariant::factory()->create(['weight_value' => 2.0, 'weight_unit' => 'kg']);
556+
$variantKg->stock = 100;
557+
Price::factory()->create([
558+
'price' => 500, 'min_quantity' => 1, 'currency_id' => $currency->id,
559+
'priceable_type' => $variantKg->getMorphClass(), 'priceable_id' => $variantKg->id,
560+
]);
561+
562+
$variantG = ProductVariant::factory()->create(['weight_value' => 1500.0, 'weight_unit' => 'g']);
563+
$variantG->stock = 100;
564+
Price::factory()->create([
565+
'price' => 500, 'min_quantity' => 1, 'currency_id' => $currency->id,
566+
'priceable_type' => $variantG->getMorphClass(), 'priceable_id' => $variantG->id,
567+
]);
568+
569+
$cart = Cart::factory()->create(['currency_id' => $currency->id]);
570+
$cart->lines()->createMany([
571+
['purchasable_type' => $variantKg->getMorphClass(), 'purchasable_id' => $variantKg->id, 'quantity' => 1],
572+
['purchasable_type' => $variantG->getMorphClass(), 'purchasable_id' => $variantG->id, 'quantity' => 2],
573+
]);
574+
$cart = $cart->calculate();
575+
576+
$option = (new ShipBy)->resolve(new ShippingOptionRequest(
577+
shippingRate: $shippingRate,
578+
cart: $cart,
579+
));
580+
581+
expect($option)->toBeInstanceOf(ShippingOption::class)
582+
->and($option->price->value)->toEqual(400);
583+
});

0 commit comments

Comments
 (0)