Files
zooqueenandHanzo Dev c91ebb4a47 billing: a wallet sale asks Square again instead of guessing, and seats are bounded
An authorization with no answer is sent again under its key; a capture with
no answer is settled by reading the payment back, taking one still held. Only
a payment Square says it did not take lets the attempt go; one that stays
unknown seals the attempt (502), so its key never pays twice, and is named
for reconciliation. Everything after the authorization runs without the
buyer's request. Square's own 4xx is a processor.Answer; anything else may be
a call that never got one. A first invoice that is not written is tried twice
and reconciled. Nothing charged and the sale cannot go on now is 503.

Seats are at most a per-seat plan's maxMembers, else 10000, on subscribe,
create and PATCH, so price times seats never wraps.

A subscription's plan snapshot carries its catalog slug, so a reader can
match it to GET /v1/billing/plans.

Co-authored-by: Hanzo Dev <[email protected]>
2026-10-15 22:26:31 -07:00

33 lines
1.1 KiB
Go

package square
import (
"errors"
"net/http"
"testing"
"github.com/square/square-go-sdk/v3/core"
)
// Square's own no is an answer: nothing was done. A server error, a timeout or a
// dropped connection may have done it, so it is not.
func TestSaidMarksOnlySquaresOwnRefusals(t *testing.T) {
for _, tc := range []struct {
err error
want bool
}{
{core.NewAPIError(http.StatusPaymentRequired, nil, errors.New("CARD_DECLINED")), true},
{core.NewAPIError(http.StatusBadRequest, nil, errors.New("payment is CANCELED")), true},
{core.NewAPIError(http.StatusTooManyRequests, nil, errors.New("RATE_LIMITED")), true},
{core.NewAPIError(http.StatusRequestTimeout, nil, errors.New("timeout")), false},
{core.NewAPIError(http.StatusInternalServerError, nil, errors.New("boom")), false},
{core.NewAPIError(http.StatusBadGateway, nil, errors.New("bad gateway")), false},
{errors.New("connection reset"), false},
} {
var a interface{ Answered() bool }
got := errors.As(said(tc.err), &a) && a.Answered()
if got != tc.want {
t.Errorf("said(%v) answered=%v, want %v", tc.err, got, tc.want)
}
}
}