package repositories import ( "context" "database/sql" "errors" "log" "FamilyHub/src/domain" ) type ReceiptsRepository interface { Create(ctx context.Context, receipt *domain.Receipt) (int64, error) GetByID(ctx context.Context, id int64) (*domain.Receipt, error) GetAll(ctx context.Context, limit, offset int) ([]*domain.Receipt, error) Update(ctx context.Context, receipt *domain.Receipt) error Delete(ctx context.Context, id int64) error } type ReceiptsSQLRepository struct { db *sql.DB } func NewReceiptsSQLRepository(db *sql.DB) *ReceiptsSQLRepository { return &ReceiptsSQLRepository{db: db} } func (r *ReceiptsSQLRepository) Create(ctx context.Context, receipt *domain.Receipt) (int64, error) { log.Printf("%+v\n", receipt) tx, err := r.db.BeginTx(ctx, nil) if err != nil { return 0, err } defer tx.Rollback() if receipt.ReceiptNumber != receipt.UI { receipt.ReceiptNumber = receipt.UI } log.Println("First query") query := ` INSERT INTO receipts ( transaction_id, receipt_number, ui, status, issued_at, total_amount, payment_amount, cash_amount, another_amount, clearing_amount, margin, currency, payment_type, cashbox_number, cashier, name_spd, name_to, name_np, type_np, street_to, house_to, kod_soato, oblast_soato, rayon_soato, selsovet_soato, doc_num, skno_number, unp, success ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29 ) RETURNING id; ` args := []any{ receipt.TransactionID, receipt.ReceiptNumber, receipt.UI, receipt.Status, receipt.IssuedAt, receipt.TotalAmount, receipt.PaymentAmount, receipt.CashAmount, receipt.AnotherAmount, receipt.ClearingAmount, receipt.Margin, receipt.Currency, receipt.PaymentType, receipt.CashboxNumber, receipt.Cashier, receipt.NameSPD, receipt.NameTO, receipt.NameNP, receipt.TypeNP, receipt.StreetTo, receipt.HouseTo, receipt.KodSoato, receipt.OblastSoato, receipt.RayonSoato, receipt.SelsovetSoato, receipt.DocNum, receipt.SknoNumber, receipt.UNP, receipt.Success, } log.Printf("SQL: %s", query) log.Printf("ARGS: %+v", args) var receiptID int64 err = tx.QueryRowContext(ctx, query, args...).Scan(&receiptID) if err != nil { return 0, err } log.Println("Second query") stmt, err := tx.PrepareContext(ctx, ` INSERT INTO positions ( receipt_id, section_number, gtin_code, product_name, product_count, amount, discount, surcharge, tag, marking_code, ukz_code ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11 ) `) if err != nil { return 0, err } defer stmt.Close() for _, p := range receipt.Positions { _, err = stmt.ExecContext( ctx, receiptID, p.SectionNumber, p.GTINCode, p.ProductName, p.ProductCount, p.Amount, p.Discount, p.Surcharge, p.Tag, p.MarkingCode, p.UKZCode, ) if err != nil { return 0, err } } if err = tx.Commit(); err != nil { return 0, err } return receiptID, nil } func (r *ReceiptsSQLRepository) GetByID(ctx context.Context, id int64) (*domain.Receipt, error) { var receipt domain.Receipt err := r.db.QueryRowContext(ctx, ` SELECT id, transaction_id, receipt_number, ui, status, issued_at, total_amount, payment_amount, cash_amount, another_amount, clearing_amount, margin, currency, payment_type, cashbox_number, cashier, name_spd, name_to, name_np, type_np, street_to, house_to, kod_soato, oblast_soato, rayon_soato, selsovet_soato, doc_num, skno_number, unp, success FROM receipts WHERE id = $1 `, id).Scan( &receipt.ID, &receipt.TransactionID, &receipt.ReceiptNumber, &receipt.UI, &receipt.Status, &receipt.IssuedAt, &receipt.TotalAmount, &receipt.PaymentAmount, &receipt.CashAmount, &receipt.AnotherAmount, &receipt.ClearingAmount, &receipt.Margin, &receipt.Currency, &receipt.PaymentType, &receipt.CashboxNumber, &receipt.Cashier, &receipt.NameSPD, &receipt.NameTO, &receipt.NameNP, &receipt.TypeNP, &receipt.StreetTo, &receipt.HouseTo, &receipt.KodSoato, &receipt.OblastSoato, &receipt.RayonSoato, &receipt.SelsovetSoato, &receipt.DocNum, &receipt.SknoNumber, &receipt.UNP, &receipt.Success, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, err } rows, err := r.db.QueryContext(ctx, ` SELECT id, receipt_id, section_number, gtin_code, product_name, product_count, amount, discount, surcharge, tag, marking_code, ukz_code FROM positions WHERE receipt_id = $1 `, id) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var p domain.Position if err := rows.Scan( &p.ID, &p.ReceiptID, &p.SectionNumber, &p.GTINCode, &p.ProductName, &p.ProductCount, &p.Amount, &p.Discount, &p.Surcharge, &p.Tag, &p.MarkingCode, &p.UKZCode, ); err != nil { return nil, err } receipt.Positions = append(receipt.Positions, p) } return &receipt, nil } func (r *ReceiptsSQLRepository) GetAll(ctx context.Context, limit, offset int) ([]*domain.Receipt, error) { rows, err := r.db.QueryContext(ctx, ` SELECT id, transaction_id, receipt_number, issued_at, total_amount, currency FROM receipts ORDER BY issued_at DESC LIMIT $1 OFFSET $2 `, limit, offset) if err != nil { return nil, err } defer rows.Close() var receipts []*domain.Receipt for rows.Next() { var rct domain.Receipt if err := rows.Scan( &rct.ID, &rct.TransactionID, &rct.ReceiptNumber, &rct.IssuedAt, &rct.TotalAmount, &rct.Currency, ); err != nil { return nil, err } receipts = append(receipts, &rct) } if err := rows.Err(); err != nil { return nil, err } return receipts, nil } func (r *ReceiptsSQLRepository) Update(ctx context.Context, receipt *domain.Receipt) error { tx, err := r.db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() _, err = tx.ExecContext(ctx, ` UPDATE receipts SET transaction_id = $1, issued_at = $2, total_amount = $3, currency = $4 WHERE id = $5 `, receipt.TransactionID, receipt.IssuedAt, receipt.TotalAmount, receipt.Currency, receipt.ID, ) if err != nil { return err } _, err = tx.ExecContext(ctx, `DELETE FROM positions WHERE receipt_id = $1`, receipt.ID) if err != nil { return err } for _, p := range receipt.Positions { _, err = tx.ExecContext(ctx, ` INSERT INTO positions ( receipt_id, product_name, product_count, amount ) VALUES ($1, $2, $3, $4) `, receipt.ID, p.ProductName, p.ProductCount, p.Amount) if err != nil { return err } } return tx.Commit() } func (r *ReceiptsSQLRepository) Delete(ctx context.Context, id int64) error { _, err := r.db.ExecContext(ctx, `DELETE FROM receipts WHERE id = $1`, id, ) return err }