feat(loyalty): show what an order earned on the order and receipt

Adds points_earned and coins_earned to the order response
(docs/prd-point-coin.md F3, PC-205). The POS prints the receipt from this
response, so the receipt gets them too.

The values are the sums of the order's EARN rows, read in one query for a
list of orders. They are filled for create, add items, update, detail and
list, and are 0 for an order that earned nothing. UpdateOrder earns before
building its response, so a payment completed there already shows the
earning. A failure to read them is logged and leaves them at 0 rather than
failing the order read. The self-order session listing reads orders
directly from the repository and still shows 0.

The two order hooks are merged into one OrderLoyalty interface (paid,
refunded, earned by orders) with a single SetLoyalty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efrilm
2026-09-30 10:50:37 +07:00
co-authored by Claude Opus 5.5
parent eb5b63677f
commit fc97c78300
10 changed files with 194 additions and 53 deletions
@@ -161,6 +161,8 @@ func OrderModelToContract(resp *models.OrderResponse) *contract.OrderResponse {
TotalPaid: resp.TotalPaid,
PaymentCount: resp.PaymentCount,
SplitType: resp.SplitType,
PointsEarned: resp.PointsEarned,
CoinsEarned: resp.CoinsEarned,
}
}
@@ -1,11 +1,14 @@
package transformer
import (
"encoding/json"
"testing"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -46,3 +49,14 @@ func TestAddToOrderContractToModelCarriesWeight(t *testing.T) {
require.NotNil(t, result.OrderItems[0].Weight)
require.Equal(t, weight, *result.OrderItems[0].Weight)
}
func TestOrderModelToContractCarriesEarnings(t *testing.T) {
got := OrderModelToContract(&models.OrderResponse{PointsEarned: 875, CoinsEarned: 3})
assert.Equal(t, int64(875), got.PointsEarned)
assert.Equal(t, int64(3), got.CoinsEarned)
body, err := json.Marshal(OrderModelToContract(&models.OrderResponse{}))
assert.NoError(t, err)
assert.Contains(t, string(body), `"points_earned":0`, "present as 0 when nothing was earned")
assert.Contains(t, string(body), `"coins_earned":0`)
}