feat(promotion-code): Complete promotion code integration and testing
- Add comprehensive promotion code methods to Order model - Implement Stripe invoice integration for promotion code discounts - Display promotion codes on invoice with proper discount breakdown - Fix and enhance all unit tests for promotion code functionality - Add discount calculation with capping to prevent negative totals - Ensure promotion codes work across entire order lifecycle 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ class Promoter::PromotionCodesController < ApplicationController
|
||||
@promotion_codes = @event.promotion_codes.includes(:user)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# GET /promoter/events/:event_id/promotion_codes/new
|
||||
# Show form to create a new promotion code
|
||||
def new
|
||||
|
||||
@@ -96,7 +96,7 @@ class Order < ApplicationRecord
|
||||
discount_total = promotion_codes.sum(:discount_amount_cents)
|
||||
|
||||
# Ensure total doesn't go below zero
|
||||
final_total = [ticket_total - discount_total, 0].max
|
||||
final_total = [ ticket_total - discount_total, 0 ].max
|
||||
update!(total_amount_cents: final_total)
|
||||
end
|
||||
|
||||
@@ -110,9 +110,9 @@ class Order < ApplicationRecord
|
||||
subtotal_amount_cents / 100.0
|
||||
end
|
||||
|
||||
# Total discount amount from all promotion codes
|
||||
# Total discount amount from all promotion codes (capped at subtotal)
|
||||
def discount_amount_cents
|
||||
promotion_codes.sum(:discount_amount_cents)
|
||||
[ promotion_codes.sum(:discount_amount_cents), subtotal_amount_cents ].min
|
||||
end
|
||||
|
||||
# Discount amount in euros
|
||||
|
||||
@@ -166,6 +166,23 @@ class StripeInvoiceService
|
||||
})
|
||||
end
|
||||
|
||||
# Add promotion code discounts as negative line items
|
||||
@order.promotion_codes.each do |promo_code|
|
||||
Stripe::InvoiceItem.create({
|
||||
customer: customer.id,
|
||||
invoice: invoice.id,
|
||||
amount: -promo_code.discount_amount_cents, # Negative amount for discount
|
||||
currency: "eur",
|
||||
description: "Réduction promotionnelle (Code: #{promo_code.code})",
|
||||
metadata: {
|
||||
promotion_code_id: promo_code.id,
|
||||
promotion_code: promo_code.code,
|
||||
discount_amount_cents: promo_code.discount_amount_cents,
|
||||
type: "promotion_discount"
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
# No service fee on customer invoice; platform fee deducted from promoter payout
|
||||
end
|
||||
|
||||
|
||||
@@ -121,13 +121,56 @@
|
||||
<% end %>
|
||||
</tbody>
|
||||
<tfoot class="bg-gray-50">
|
||||
<!-- Subtotal -->
|
||||
<tr>
|
||||
<th colspan="3" scope="col" class="px-6 py-3 text-right text-sm font-medium text-gray-900 uppercase tracking-wider">Total</th>
|
||||
<th scope="col" class="px-6 py-3 text-right text-lg font-bold text-gray-900"><%= "%.2f" % @order.total_amount_euros %>€</th>
|
||||
<td colspan="3" scope="col" class="px-6 py-3 text-right text-sm font-medium text-gray-600">Sous-total</td>
|
||||
<td scope="col" class="px-6 py-3 text-right text-sm font-medium text-gray-600"><%= "%.2f" % @order.subtotal_amount_euros %>€</td>
|
||||
</tr>
|
||||
|
||||
<!-- Promotion Code Discounts -->
|
||||
<% if @order.promotion_codes.any? %>
|
||||
<% @order.promotion_codes.each do |promo_code| %>
|
||||
<tr>
|
||||
<td colspan="3" scope="col" class="px-6 py-3 text-right text-sm font-medium text-green-600">
|
||||
Réduction (Code: <%= promo_code.code %>)
|
||||
</td>
|
||||
<td scope="col" class="px-6 py-3 text-right text-sm font-semibold text-green-600">-<%= "%.2f" % promo_code.discount_amount_euros %>€</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<!-- Total -->
|
||||
<tr class="border-t-2 border-gray-300">
|
||||
<td colspan="3" scope="col" class="px-6 py-3 text-right text-lg font-bold text-gray-900 uppercase tracking-wider">Total</td>
|
||||
<td scope="col" class="px-6 py-3 text-right text-lg font-bold text-gray-900">
|
||||
<% if @order.total_amount_cents == 0 %>
|
||||
GRATUIT
|
||||
<% else %>
|
||||
<%= "%.2f" % @order.total_amount_euros %>€
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Promotion Code Summary -->
|
||||
<% if @order.promotion_codes.any? %>
|
||||
<div class="mt-4 p-4 bg-green-50 border border-green-200 rounded-lg">
|
||||
<h4 class="text-sm font-semibold text-green-900 mb-2 flex items-center">
|
||||
<i data-lucide="tag" class="w-4 h-4 mr-2"></i>
|
||||
Codes promotionnels appliqués
|
||||
</h4>
|
||||
<div class="text-xs text-green-700">
|
||||
<% @order.promotion_codes.each do |promo_code| %>
|
||||
<div class="flex items-center justify-between">
|
||||
<span><%= promo_code.code %></span>
|
||||
<span class="font-semibold">-<%= "%.2f" % promo_code.discount_amount_euros %>€</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Payment Information -->
|
||||
|
||||
Reference in New Issue
Block a user