feat(payments): report direct-rail income to «Мой налог» #295
@@ -661,6 +661,11 @@ func TestMyNalogBuyerMails(t *testing.T) {
|
||||
if !strings.Contains(first[0].Text, "не чек") {
|
||||
t.Errorf("the purchase letter does not say it is not the receipt:\n%s", first[0].Text)
|
||||
}
|
||||
// The catalog title already names the pack size, so appending it again read as
|
||||
// "50 фишек — 50 фишек". The line is the title verbatim, then the price, and nothing else.
|
||||
if !strings.Contains(first[0].Text, "Покупка совершена: test pack, 149.00 ₽.") {
|
||||
t.Errorf("the purchase line is not the catalog title plus the price:\n%s", first[0].Text)
|
||||
}
|
||||
|
||||
// 2. The receipt letter, once the income is filed, carrying the printable link.
|
||||
if _, err := exp.RunBatch(ctx, time.Minute); err != nil {
|
||||
|
||||
@@ -185,15 +185,18 @@ func (m *Mailer) stampReceipt(ctx context.Context, mark func(context.Context, uu
|
||||
}
|
||||
}
|
||||
|
||||
// describe renders what was bought in one line.
|
||||
func describe(title string, chips int, amountMinor int64, currency string) string {
|
||||
// describe renders what was bought in one line: the catalog title exactly as the buyer saw it on
|
||||
// the storefront, then the price.
|
||||
//
|
||||
// The pack size is deliberately NOT appended. Catalog titles already name it ("50 фишек"), so
|
||||
// adding it produced "50 фишек — 50 фишек". The title is the single source of that wording; the
|
||||
// tax receipt states the quantity separately in the form the tax service wants (see
|
||||
// mynalog.IncomeName), which is a different surface with different requirements.
|
||||
func describe(title string, amountMinor int64, currency string) string {
|
||||
what := strings.TrimSpace(title)
|
||||
if what == "" {
|
||||
what = "покупка в игре"
|
||||
}
|
||||
if chips > 0 {
|
||||
what = fmt.Sprintf("%s — %d фишек", what, chips)
|
||||
}
|
||||
return fmt.Sprintf("%s, %s", what, formatAmount(amountMinor, currency))
|
||||
}
|
||||
|
||||
@@ -224,7 +227,7 @@ func purchaseText(p payments.PurchaseMail) string {
|
||||
отдельным письмом: обычно в течение часа, но иногда это занимает до нескольких дней.
|
||||
|
||||
Спасибо, что играете в «Эрудит».
|
||||
`, describe(p.Title, p.Chips, p.AmountMinor, p.Currency), p.OrderID)
|
||||
`, describe(p.Title, p.AmountMinor, p.Currency), p.OrderID)
|
||||
}
|
||||
|
||||
// receiptText is the fiscal receipt letter, which is how the receipt is actually handed to the
|
||||
@@ -240,7 +243,7 @@ func receiptText(r payments.ReceiptMail, inn, baseURL string, loc *time.Location
|
||||
|
||||
Продавец применяет налог на профессиональный доход; чек сформирован в сервисе
|
||||
«Мой налог» Федеральной налоговой службы.
|
||||
`, describe(r.Title, r.Chips, r.AmountMinor, r.Currency),
|
||||
`, describe(r.Title, r.AmountMinor, r.Currency),
|
||||
r.OperationTime.In(loc).Format("02.01.2006 15:04"),
|
||||
mynalog.ReceiptURL(baseURL, inn, r.ReceiptUUID))
|
||||
}
|
||||
@@ -255,6 +258,6 @@ func cancelText(r payments.ReceiptMail, loc *time.Location) string {
|
||||
|
||||
%s
|
||||
Дата покупки: %s
|
||||
`, describe(r.Title, r.Chips, r.AmountMinor, r.Currency),
|
||||
`, describe(r.Title, r.AmountMinor, r.Currency),
|
||||
r.OperationTime.In(loc).Format("02.01.2006 15:04"))
|
||||
}
|
||||
|
||||
@@ -125,7 +125,6 @@ type PurchaseMail struct {
|
||||
OrderID uuid.UUID
|
||||
Origin string
|
||||
Title string
|
||||
Chips int
|
||||
AmountMinor int64
|
||||
Currency string
|
||||
CreatedAt time.Time
|
||||
@@ -137,7 +136,6 @@ type ReceiptMail struct {
|
||||
AccountID uuid.UUID
|
||||
ReceiptUUID string
|
||||
Title string
|
||||
Chips int
|
||||
AmountMinor int64
|
||||
Currency string
|
||||
OperationTime time.Time
|
||||
|
||||
@@ -476,7 +476,7 @@ func (s *Store) pendingPurchaseMails(ctx context.Context, limit int) ([]Purchase
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT e.event_id, e.account_id, e.order_id, COALESCE(o.origin, ''),
|
||||
COALESCE(o.expected_amount, 0), COALESCE(o.currency, ''),
|
||||
COALESCE(p.title, ''), COALESCE((e.payload->>'chips')::int, 0), e.created_at
|
||||
COALESCE(p.title, ''), e.created_at
|
||||
FROM payments.payment_events e
|
||||
LEFT JOIN payments.orders o ON o.order_id = e.order_id
|
||||
LEFT JOIN payments.product p ON p.product_id = o.product_id
|
||||
@@ -495,7 +495,7 @@ func (s *Store) pendingPurchaseMails(ctx context.Context, limit int) ([]Purchase
|
||||
orderID uuid.NullUUID
|
||||
)
|
||||
if err := rows.Scan(&m.EventID, &m.AccountID, &orderID, &m.Origin, &m.AmountMinor,
|
||||
&m.Currency, &m.Title, &m.Chips, &m.CreatedAt); err != nil {
|
||||
&m.Currency, &m.Title, &m.CreatedAt); err != nil {
|
||||
return nil, fmt.Errorf("payments: scan purchase mail: %w", err)
|
||||
}
|
||||
m.OrderID = orderID.UUID
|
||||
@@ -551,7 +551,7 @@ func (s *Store) pendingMyNalogMails(ctx context.Context, limit int, cancelled bo
|
||||
&m.AmountMinor, &m.Currency, &m.OperationTime); err != nil {
|
||||
return nil, fmt.Errorf("payments: scan receipt mail: %w", err)
|
||||
}
|
||||
m.Title, m.Chips = describeSnapshot(snapshot.String)
|
||||
m.Title, _ = describeSnapshot(snapshot.String)
|
||||
out = append(out, m)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user