редактирование и удаление сопоставлений

список накладных с позициями
This commit is contained in:
2025-12-29 10:46:05 +03:00
parent c2d382cb6a
commit 310a64e3ba
30 changed files with 1250 additions and 8173 deletions

View File

@@ -8,20 +8,28 @@ import (
"github.com/shopspring/decimal"
"go.uber.org/zap"
"rmser/internal/domain/invoices"
"rmser/internal/domain/drafts"
invDomain "rmser/internal/domain/invoices"
"rmser/internal/domain/suppliers"
"rmser/internal/infrastructure/rms"
"rmser/pkg/logger"
)
type Service struct {
rmsClient rms.ClientI
repo invDomain.Repository
draftsRepo drafts.Repository
supplierRepo suppliers.Repository
rmsFactory *rms.Factory
// Здесь можно добавить репозитории каталога и контрагентов для валидации,
// но для краткости пока опустим глубокую валидацию.
}
func NewService(rmsClient rms.ClientI) *Service {
func NewService(repo invDomain.Repository, draftsRepo drafts.Repository, supplierRepo suppliers.Repository, rmsFactory *rms.Factory) *Service {
return &Service{
rmsClient: rmsClient,
repo: repo,
draftsRepo: draftsRepo,
supplierRepo: supplierRepo,
rmsFactory: rmsFactory,
}
}
@@ -39,7 +47,7 @@ type CreateRequestDTO struct {
}
// SendInvoiceToRMS валидирует DTO, собирает доменную модель и отправляет в RMS
func (s *Service) SendInvoiceToRMS(req CreateRequestDTO) (string, error) {
func (s *Service) SendInvoiceToRMS(req CreateRequestDTO, userID uuid.UUID) (string, error) {
// 1. Базовая валидация
if len(req.Items) == 0 {
return "", fmt.Errorf("список товаров пуст")
@@ -51,20 +59,20 @@ func (s *Service) SendInvoiceToRMS(req CreateRequestDTO) (string, error) {
}
// 2. Сборка доменной модели
inv := invoices.Invoice{
inv := invDomain.Invoice{
ID: uuid.Nil, // Новый документ
DocumentNumber: req.DocumentNumber,
DateIncoming: dateInc,
SupplierID: req.SupplierID,
DefaultStoreID: req.StoreID,
Status: "NEW",
Items: make([]invoices.InvoiceItem, 0, len(req.Items)),
Items: make([]invDomain.InvoiceItem, 0, len(req.Items)),
}
for _, itemDTO := range req.Items {
sum := itemDTO.Amount.Mul(itemDTO.Price) // Пересчитываем сумму
inv.Items = append(inv.Items, invoices.InvoiceItem{
inv.Items = append(inv.Items, invDomain.InvoiceItem{
ProductID: itemDTO.ProductID,
Amount: itemDTO.Amount,
Price: itemDTO.Price,
@@ -72,15 +80,89 @@ func (s *Service) SendInvoiceToRMS(req CreateRequestDTO) (string, error) {
})
}
// 3. Отправка через клиент
// 3. Получение клиента RMS
client, err := s.rmsFactory.GetClientForUser(userID)
if err != nil {
return "", fmt.Errorf("ошибка получения клиента RMS: %w", err)
}
// 4. Отправка через клиент
logger.Log.Info("Отправка накладной в RMS",
zap.String("supplier", req.SupplierID.String()),
zap.Int("items_count", len(inv.Items)))
docNum, err := s.rmsClient.CreateIncomingInvoice(inv)
docNum, err := client.CreateIncomingInvoice(inv)
if err != nil {
return "", err
}
return docNum, nil
}
// InvoiceDetailsDTO - DTO для ответа на запрос деталей накладной
type InvoiceDetailsDTO struct {
ID uuid.UUID `json:"id"`
Number string `json:"number"`
Date string `json:"date"`
Status string `json:"status"`
Supplier struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
} `json:"supplier"`
Items []struct {
Name string `json:"name"`
Quantity float64 `json:"quantity"`
Price float64 `json:"price"`
Total float64 `json:"total"`
} `json:"items"`
PhotoURL *string `json:"photo_url"`
}
// GetInvoice возвращает детали синхронизированной накладной по ID
func (s *Service) GetInvoice(id uuid.UUID) (*InvoiceDetailsDTO, error) {
// 1. Получить накладную из репозитория
inv, err := s.repo.GetByID(id)
if err != nil {
return nil, fmt.Errorf("ошибка получения накладной: %w", err)
}
// 2. Получить поставщика
supplier, err := s.supplierRepo.GetByID(inv.SupplierID)
if err != nil {
return nil, fmt.Errorf("ошибка получения поставщика: %w", err)
}
// 3. Проверить, есть ли draft с photo_url
var photoURL *string
draft, err := s.draftsRepo.GetByRMSInvoiceID(inv.ID)
if err == nil && draft != nil {
photoURL = &draft.SenderPhotoURL
}
// 4. Собрать DTO
dto := &InvoiceDetailsDTO{
ID: inv.ID,
Number: inv.DocumentNumber,
Date: inv.DateIncoming.Format("2006-01-02"),
Status: "COMPLETED", // Для синхронизированных накладных статус всегда COMPLETED
Items: make([]struct {
Name string `json:"name"`
Quantity float64 `json:"quantity"`
Price float64 `json:"price"`
Total float64 `json:"total"`
}, len(inv.Items)),
PhotoURL: photoURL,
}
dto.Supplier.ID = supplier.ID
dto.Supplier.Name = supplier.Name
for i, item := range inv.Items {
dto.Items[i].Name = item.Product.Name
dto.Items[i].Quantity, _ = item.Amount.Float64()
dto.Items[i].Price, _ = item.Price.Float64()
dto.Items[i].Total, _ = item.Sum.Float64()
}
return dto, nil
}