Added structured logging across services and repositories. Updated SQL queries to use parameterized placeholders for better readability and security. Enhanced error handling for external service communication. #3
@@ -7,6 +7,7 @@ import (
|
||||
"FamilyHub/src/domain"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -73,13 +74,13 @@ func (router *TransactionsRouter) Create(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%+v\n", input)
|
||||
transaction, err := router.creationService.Create(c.Request.Context(), input)
|
||||
if err != nil {
|
||||
handleTransactionError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%+v\n", transaction)
|
||||
c.JSON(http.StatusCreated, dto.TransactionToResponse(transaction))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import (
|
||||
"FamilyHub/src/domain"
|
||||
"FamilyHub/src/integrations/receiptProvider"
|
||||
"FamilyHub/src/repositories"
|
||||
"FamilyHub/src/utils"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -35,18 +37,23 @@ func (s *receiptService) AddReceipt(
|
||||
ctx context.Context,
|
||||
req domain.AddReceiptRequest,
|
||||
) (*domain.Receipt, error) {
|
||||
log.Printf("receipt add request: payload=%s", utils.ToLogJSON(req))
|
||||
|
||||
receipt, err := s.provider.GetReceipt(ctx, req.Date, req.Number)
|
||||
if err != nil {
|
||||
log.Printf("receipt add failed: err=%v payload=%s", err, utils.ToLogJSON(req))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
receiptID, err := s.repo.Create(ctx, receipt)
|
||||
if err != nil {
|
||||
log.Printf("receipt persist failed: err=%v receipt=%s", err, utils.ToLogJSON(receipt))
|
||||
return nil, err
|
||||
}
|
||||
receipt.ID = int(receiptID)
|
||||
|
||||
if !s.shouldCreateTransaction(req) {
|
||||
log.Printf("receipt add response: payload=%s", utils.ToLogJSON(receipt))
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
@@ -59,6 +66,7 @@ func (s *receiptService) AddReceipt(
|
||||
}
|
||||
|
||||
receipt.TransactionID = &transaction.ID
|
||||
log.Printf("receipt add response: payload=%s", utils.ToLogJSON(receipt))
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
@@ -94,11 +102,14 @@ func (s *receiptService) createTransactionForReceipt(
|
||||
CreatedBy: *req.CreatedBy,
|
||||
ReceiptID: &receiptID,
|
||||
}
|
||||
|
||||
log.Printf("%+v\n", transaction)
|
||||
log.Printf("receipt transaction create request: payload=%s", utils.ToLogJSON(transaction))
|
||||
if err := s.transactionRepo.Create(ctx, transaction); err != nil {
|
||||
log.Printf("receipt transaction create failed: err=%v payload=%s", err, utils.ToLogJSON(transaction))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Printf("receipt transaction create response: payload=%s", utils.ToLogJSON(transaction))
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ package services
|
||||
import (
|
||||
"FamilyHub/src/domain"
|
||||
"FamilyHub/src/repositories"
|
||||
"FamilyHub/src/utils"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -38,7 +40,10 @@ var (
|
||||
)
|
||||
|
||||
func (s *transactionService) Create(ctx context.Context, req domain.CreateTransactionRequest) (*domain.Transaction, error) {
|
||||
log.Printf("transaction create request: payload=%s", utils.ToLogJSON(req))
|
||||
|
||||
if strings.TrimSpace(req.Type) == "" || strings.TrimSpace(req.Category) == "" {
|
||||
log.Printf("transaction create failed: err=%v payload=%s", ErrInvalidTransaction, utils.ToLogJSON(req))
|
||||
return nil, ErrInvalidTransaction
|
||||
}
|
||||
|
||||
@@ -55,8 +60,10 @@ func (s *transactionService) Create(ctx context.Context, req domain.CreateTransa
|
||||
|
||||
if err := s.repo.Create(ctx, transaction); err != nil {
|
||||
if errors.Is(err, repositories.ErrReceiptNotFound) {
|
||||
log.Printf("transaction create failed: err=%v payload=%s", ErrReceiptNotFound, utils.ToLogJSON(req))
|
||||
return nil, ErrReceiptNotFound
|
||||
}
|
||||
log.Printf("transaction create failed: err=%v payload=%s", err, utils.ToLogJSON(req))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -72,6 +79,7 @@ func (s *transactionService) Create(ctx context.Context, req domain.CreateTransa
|
||||
})
|
||||
}
|
||||
|
||||
log.Printf("transaction create response: payload=%s", utils.ToLogJSON(transaction))
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,14 @@ package familyHub
|
||||
import (
|
||||
"FamilyHub/src/config"
|
||||
"FamilyHub/src/domain"
|
||||
"FamilyHub/src/utils"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -63,14 +66,13 @@ func (c *HTTPClient) SendReceipt(ctx context.Context, payload domain.AddReceiptR
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
responseBody, statusCode, err := c.doRequest(req, "familyhub_api.transactions.create", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d", resp.StatusCode)
|
||||
if statusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d body %s", statusCode, utils.TruncateForLog(string(responseBody), 512))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -120,14 +122,13 @@ func (c *HTTPClient) RegisterUser(ctx context.Context, payload domain.CreateUser
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
responseBody, statusCode, err := c.doRequest(req, "familyhub_api.users.create", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d", resp.StatusCode)
|
||||
if statusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d body %s", statusCode, utils.TruncateForLog(string(responseBody), 512))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -144,22 +145,21 @@ func (c *HTTPClient) GetUserByTelegramID(ctx context.Context, telegramID int64)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
responseBody, statusCode, err := c.doRequest(req, "familyhub_api.users.by_telegram", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
if statusCode == http.StatusNotFound {
|
||||
return nil, errUserNotFound
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return nil, fmt.Errorf("api error: status %d", resp.StatusCode)
|
||||
if statusCode >= 300 {
|
||||
return nil, fmt.Errorf("api error: status %d body %s", statusCode, utils.TruncateForLog(string(responseBody), 512))
|
||||
}
|
||||
|
||||
var user domain.UserResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
|
||||
if err := json.Unmarshal(responseBody, &user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -184,15 +184,48 @@ func (c *HTTPClient) CreateFamily(ctx context.Context, payload domain.CreateFami
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
responseBody, statusCode, err := c.doRequest(req, "familyhub_api.families.create", body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d", resp.StatusCode)
|
||||
if statusCode >= 300 {
|
||||
return fmt.Errorf("api error: status %d body %s", statusCode, utils.TruncateForLog(string(responseBody), 512))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HTTPClient) doRequest(req *http.Request, service string, requestBody []byte) ([]byte, int, error) {
|
||||
log.Printf(
|
||||
"external request: service=%s method=%s url=%s body=%q",
|
||||
service,
|
||||
req.Method,
|
||||
req.URL.String(),
|
||||
utils.TruncateForLog(string(requestBody), utils.DefaultLogValueLimit),
|
||||
)
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("external response: service=%s method=%s url=%s err=%v", service, req.Method, req.URL.String(), err)
|
||||
return nil, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
responseBody, readErr := io.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
log.Printf("external response: service=%s method=%s url=%s status=%d read_err=%v", service, req.Method, req.URL.String(), resp.StatusCode, readErr)
|
||||
return nil, resp.StatusCode, readErr
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"external response: service=%s method=%s url=%s status=%d body=%q",
|
||||
service,
|
||||
req.Method,
|
||||
req.URL.String(),
|
||||
resp.StatusCode,
|
||||
utils.TruncateForLog(string(responseBody), utils.DefaultLogValueLimit),
|
||||
)
|
||||
|
||||
return responseBody, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
@@ -2,9 +2,14 @@ package familyHub
|
||||
|
||||
import (
|
||||
"FamilyHub/src/config"
|
||||
"FamilyHub/src/utils"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -18,19 +23,42 @@ func NewBotClient(config config.Config) (*HTTPClient, error) {
|
||||
}
|
||||
|
||||
func (c *HTTPClient) SendMessage(ctx context.Context, chatId int64, message string) error {
|
||||
url := c.config.TelegramApi + "/bot" + c.config.BotToken + "/sendMessage?chat_id=" + strconv.FormatInt(chatId, 10) + "&text=" + message
|
||||
req, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
c.config.TelegramApi+"/bot"+c.config.BotToken+"/sendMessage?chat_id="+strconv.FormatInt(chatId, 10)+"&text="+message,
|
||||
url,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logURL := strings.ReplaceAll(req.URL.String(), c.config.BotToken, "***")
|
||||
log.Printf(
|
||||
"external request: service=telegram_bot.send_message method=%s url=%s body=%q",
|
||||
http.MethodGet,
|
||||
logURL,
|
||||
utils.TruncateForLog(fmt.Sprintf("chat_id=%d&text=%s", chatId, message), utils.DefaultLogValueLimit),
|
||||
)
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("external response: service=telegram_bot.send_message method=%s url=%s err=%v", http.MethodGet, logURL, err)
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
responseBody, readErr := io.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
log.Printf("external response: service=telegram_bot.send_message method=%s url=%s status=%d read_err=%v", http.MethodGet, logURL, resp.StatusCode, readErr)
|
||||
return readErr
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"external response: service=telegram_bot.send_message method=%s url=%s status=%d body=%q",
|
||||
http.MethodGet,
|
||||
logURL,
|
||||
resp.StatusCode,
|
||||
utils.TruncateForLog(string(responseBody), utils.DefaultLogValueLimit),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package ocr
|
||||
|
||||
import (
|
||||
"FamilyHub/src/utils"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
vision "cloud.google.com/go/vision/apiv1"
|
||||
)
|
||||
@@ -30,19 +32,29 @@ func (g *GoogleOCR) Close() error {
|
||||
}
|
||||
|
||||
func (g *GoogleOCR) Recognize(ctx context.Context, image []byte) (string, error) {
|
||||
log.Printf("external request: service=google_ocr.detect_text image_size_bytes=%d", len(image))
|
||||
|
||||
img, err := vision.NewImageFromReader(bytes.NewReader(image))
|
||||
if err != nil {
|
||||
log.Printf("external response: service=google_ocr.detect_text err=%v", err)
|
||||
return "", fmt.Errorf("load image: %w", err)
|
||||
}
|
||||
|
||||
annotations, err := g.client.DetectTexts(ctx, img, nil, 1)
|
||||
if err != nil {
|
||||
log.Printf("external response: service=google_ocr.detect_text err=%v", err)
|
||||
return "", fmt.Errorf("detect text: %w", err)
|
||||
}
|
||||
|
||||
if len(annotations) == 0 {
|
||||
log.Printf("external response: service=google_ocr.detect_text result=%q", "")
|
||||
return "", nil
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"external response: service=google_ocr.detect_text result=%q annotations=%d",
|
||||
utils.TruncateForLog(annotations[0].Description, utils.DefaultLogValueLimit),
|
||||
len(annotations),
|
||||
)
|
||||
return annotations[0].Description, nil
|
||||
}
|
||||
|
||||
@@ -64,6 +64,14 @@ func (s *receiptProvider) GetReceipt(
|
||||
var receipt domain.Receipt
|
||||
|
||||
body, contentType := buildMultipartBody(date, number)
|
||||
requestBody := body.String()
|
||||
log.Printf(
|
||||
"external request: service=receipt_provider method=%s url=%s content_type=%s body=%q",
|
||||
http.MethodPost,
|
||||
url,
|
||||
contentType,
|
||||
utils.TruncateForLog(requestBody, utils.DefaultLogValueLimit),
|
||||
)
|
||||
httpReq, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
@@ -79,18 +87,27 @@ func (s *receiptProvider) GetReceipt(
|
||||
|
||||
resp, err := s.client.Do(httpReq)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
log.Printf("external response: service=receipt_provider method=%s url=%s err=%v", http.MethodPost, url, err)
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
responseBody, readErr := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||
responseBody, readErr := io.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
log.Printf("failed to read external service error body: %v", readErr)
|
||||
log.Printf("failed to read external service response body: %v", readErr)
|
||||
return nil, readErr
|
||||
}
|
||||
|
||||
bodyText := strings.TrimSpace(string(responseBody))
|
||||
log.Printf("external service returned %d body=%q", resp.StatusCode, bodyText)
|
||||
log.Printf(
|
||||
"external response: service=receipt_provider method=%s url=%s status=%d body=%q",
|
||||
http.MethodPost,
|
||||
url,
|
||||
resp.StatusCode,
|
||||
utils.TruncateForLog(bodyText, utils.DefaultLogValueLimit),
|
||||
)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, &ExternalServiceError{
|
||||
StatusCode: resp.StatusCode,
|
||||
Body: bodyText,
|
||||
@@ -100,8 +117,8 @@ func (s *receiptProvider) GetReceipt(
|
||||
var raw struct {
|
||||
Message map[string]interface{} `json:"message"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&raw); err != nil {
|
||||
log.Printf("external service returned %s\n", err.Error())
|
||||
if err := json.Unmarshal(responseBody, &raw); err != nil {
|
||||
log.Printf("external service returned invalid json: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -112,6 +129,7 @@ func (s *receiptProvider) GetReceipt(
|
||||
}
|
||||
|
||||
if receipt.IssuedAtRaw == "" {
|
||||
log.Printf("external response parse failed: service=receipt_provider err=%v date=%s number=%s", ErrReceiptNotFound, date, number)
|
||||
return nil, ErrReceiptNotFound
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"FamilyHub/src/domain"
|
||||
)
|
||||
@@ -25,29 +26,63 @@ func NewReceiptsSQLRepository(db *sql.DB) *ReceiptsSQLRepository {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
res, err := tx.ExecContext(ctx, `
|
||||
|
||||
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,
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
)
|
||||
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,
|
||||
@@ -85,16 +120,19 @@ func (r *ReceiptsSQLRepository) Create(ctx context.Context, receipt *domain.Rece
|
||||
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
|
||||
}
|
||||
|
||||
receiptID, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
log.Println("Second query")
|
||||
|
||||
stmt, err := tx.PrepareContext(ctx, `
|
||||
INSERT INTO positions (
|
||||
@@ -109,7 +147,11 @@ func (r *ReceiptsSQLRepository) Create(ctx context.Context, receipt *domain.Rece
|
||||
tag,
|
||||
marking_code,
|
||||
ukz_code
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9, $10, $11
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -117,7 +159,8 @@ func (r *ReceiptsSQLRepository) Create(ctx context.Context, receipt *domain.Rece
|
||||
defer stmt.Close()
|
||||
|
||||
for _, p := range receipt.Positions {
|
||||
_, err = stmt.ExecContext(ctx,
|
||||
_, err = stmt.ExecContext(
|
||||
ctx,
|
||||
receiptID,
|
||||
p.SectionNumber,
|
||||
p.GTINCode,
|
||||
@@ -135,7 +178,11 @@ func (r *ReceiptsSQLRepository) Create(ctx context.Context, receipt *domain.Rece
|
||||
}
|
||||
}
|
||||
|
||||
return receiptID, tx.Commit()
|
||||
if err = tx.Commit(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return receiptID, nil
|
||||
}
|
||||
|
||||
func (r *ReceiptsSQLRepository) GetByID(ctx context.Context, id int64) (*domain.Receipt, error) {
|
||||
@@ -157,7 +204,7 @@ func (r *ReceiptsSQLRepository) GetByID(ctx context.Context, id int64) (*domain.
|
||||
doc_num, skno_number, unp,
|
||||
success
|
||||
FROM receipts
|
||||
WHERE id = ?
|
||||
WHERE id = $1
|
||||
`, id).Scan(
|
||||
&receipt.ID,
|
||||
&receipt.TransactionID,
|
||||
@@ -213,7 +260,7 @@ func (r *ReceiptsSQLRepository) GetByID(ctx context.Context, id int64) (*domain.
|
||||
product_count, amount,
|
||||
discount, surcharge,
|
||||
tag, marking_code, ukz_code
|
||||
FROM positions WHERE receipt_id = ?
|
||||
FROM positions WHERE receipt_id = $1
|
||||
`, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -247,10 +294,16 @@ func (r *ReceiptsSQLRepository) GetByID(ctx context.Context, id int64) (*domain.
|
||||
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
|
||||
SELECT
|
||||
id,
|
||||
transaction_id,
|
||||
receipt_number,
|
||||
issued_at,
|
||||
total_amount,
|
||||
currency
|
||||
FROM receipts
|
||||
ORDER BY issued_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
LIMIT $1 OFFSET $2
|
||||
`, limit, offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -261,6 +314,7 @@ func (r *ReceiptsSQLRepository) GetAll(ctx context.Context, limit, offset int) (
|
||||
|
||||
for rows.Next() {
|
||||
var rct domain.Receipt
|
||||
|
||||
if err := rows.Scan(
|
||||
&rct.ID,
|
||||
&rct.TransactionID,
|
||||
@@ -271,9 +325,14 @@ func (r *ReceiptsSQLRepository) GetAll(ctx context.Context, limit, offset int) (
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
receipts = append(receipts, &rct)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return receipts, nil
|
||||
}
|
||||
|
||||
@@ -287,11 +346,11 @@ func (r *ReceiptsSQLRepository) Update(ctx context.Context, receipt *domain.Rece
|
||||
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
UPDATE receipts SET
|
||||
transaction_id = ?,
|
||||
issued_at = ?,
|
||||
total_amount = ?,
|
||||
currency = ?
|
||||
WHERE id = ?
|
||||
transaction_id = $1,
|
||||
issued_at = $2,
|
||||
total_amount = $3,
|
||||
currency = $4
|
||||
WHERE id = $5
|
||||
`,
|
||||
receipt.TransactionID,
|
||||
receipt.IssuedAt,
|
||||
@@ -303,7 +362,7 @@ func (r *ReceiptsSQLRepository) Update(ctx context.Context, receipt *domain.Rece
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `DELETE FROM positions WHERE receipt_id = ?`, receipt.ID)
|
||||
_, err = tx.ExecContext(ctx, `DELETE FROM positions WHERE receipt_id = $1`, receipt.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -312,7 +371,7 @@ func (r *ReceiptsSQLRepository) Update(ctx context.Context, receipt *domain.Rece
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO positions (
|
||||
receipt_id, product_name, product_count, amount
|
||||
) VALUES (?, ?, ?, ?)
|
||||
) VALUES ($1, $2, $3, $4)
|
||||
`, receipt.ID, p.ProductName, p.ProductCount, p.Amount)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -324,7 +383,7 @@ func (r *ReceiptsSQLRepository) Update(ctx context.Context, receipt *domain.Rece
|
||||
|
||||
func (r *ReceiptsSQLRepository) Delete(ctx context.Context, id int64) error {
|
||||
_, err := r.db.ExecContext(ctx,
|
||||
`DELETE FROM receipts WHERE id = ?`,
|
||||
`DELETE FROM receipts WHERE id = $1`,
|
||||
id,
|
||||
)
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const DefaultLogValueLimit = 4096
|
||||
|
||||
func ToLogJSON(value any) string {
|
||||
if value == nil {
|
||||
return "null"
|
||||
}
|
||||
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return TruncateForLog(fmt.Sprintf("%+v", value), DefaultLogValueLimit)
|
||||
}
|
||||
|
||||
return TruncateForLog(string(data), DefaultLogValueLimit)
|
||||
}
|
||||
|
||||
func TruncateForLog(value string, limit int) string {
|
||||
if limit <= 0 || len(value) <= limit {
|
||||
return value
|
||||
}
|
||||
|
||||
return value[:limit] + "...(truncated)"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"id": 0,
|
||||
"transaction_id": null,
|
||||
"STATUS": 1,
|
||||
"another_amount": 0,
|
||||
"cash_amount": 0,
|
||||
"cashbox_number": 119091676,
|
||||
"cashier": "Старший кассир КСО",
|
||||
"clearing_amount": 190.06,
|
||||
"currency": "BYN",
|
||||
"doc_num": "39972",
|
||||
"house_to": "11",
|
||||
"kod_soato": "5000000000",
|
||||
"margin": 0,
|
||||
"name_np": "Минск",
|
||||
"name_spd": "Общество с ограниченной ответственностью \"ГРИНрозница\"",
|
||||
"name_to": "Магазин \"ГРИН-5\"",
|
||||
"oblast_soato": null,
|
||||
"rayon_soato": null,
|
||||
"selsovet_soato": null,
|
||||
"payment_amount": 190.06,
|
||||
"payment_type": 1,
|
||||
"receipt_number": "CBB580D6268681CB071931DC",
|
||||
"skno_number": "AVQ24170126963",
|
||||
"street_to": "УЛ. ПЕТРА МСТИСЛАВЦА",
|
||||
"success": "A check is correct",
|
||||
"total_amount": 190.06,
|
||||
"type_np": "г.",
|
||||
"ui": "CBB580D6268681CB071931DC",
|
||||
"unp": "191634233",
|
||||
"issued_at": "09/11/2025, 18:08:31"
|
||||
}
|
||||
Reference in New Issue
Block a user