Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.43% covered (success)
96.43%
27 / 28
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApplyCouponAction
96.43% covered (success)
96.43%
27 / 28
50.00% covered (danger)
50.00%
1 / 2
2
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Billing\Application\Actions;
6
7use ImovelZapAi\Billing\Application\Services\CouponCalculator;
8use ImovelZapAi\Billing\Domain\Enums\BillingCycle;
9use ImovelZapAi\Billing\Infrastructure\Persistence\Eloquent\BillingCouponRedemptionModel;
10use ImovelZapAi\Organizations\Infrastructure\Persistence\Eloquent\OrganizationSubscriptionModel;
11
12final class ApplyCouponAction
13{
14    public function __construct(
15        private readonly CouponCalculator $coupons,
16    ) {}
17
18    /**
19     * @return array{discount_cents: int, amount_cents: int, coupon_code: string}
20     */
21    public function execute(string $tenantId, string $couponCode): array
22    {
23        $subscription = OrganizationSubscriptionModel::query()
24            ->with('plan')
25            ->where('tenant_id', $tenantId)
26            ->firstOrFail();
27
28        $plan = $subscription->plan;
29        $cycle = BillingCycle::tryFrom((string) ($subscription->billing_cycle ?? 'monthly'))
30            ?? BillingCycle::Monthly;
31
32        $coupon = $this->coupons->findValid($couponCode);
33        $this->coupons->assertApplicable($coupon, $plan);
34
35        $discount = $this->coupons->discountCents($coupon, $plan, $cycle);
36        $amount = $this->coupons->amountAfterDiscount($plan, $cycle, $coupon);
37
38        $subscription->forceFill(['coupon_code' => $coupon->code])->save();
39
40        BillingCouponRedemptionModel::query()->updateOrCreate(
41            [
42                'billing_coupon_id' => $coupon->id,
43                'tenant_id' => $tenantId,
44            ],
45            [
46                'organization_subscription_id' => $subscription->id,
47                'discount_cents' => $discount,
48            ],
49        );
50
51        return [
52            'discount_cents' => $discount,
53            'amount_cents' => $amount,
54            'coupon_code' => (string) $coupon->code,
55        ];
56    }
57}