mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
2701-есть флоу для оператора и красивый список накладных
This commit is contained in:
@@ -689,3 +689,168 @@ func (s *Service) GetInvoiceDetails(invoiceID, userID uuid.UUID) (*invoices.Invo
|
||||
|
||||
return inv, photoURL, nil
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// === МЕТОДЫ ДЛЯ IN-CHAT DRAFT EDITOR ===
|
||||
// ============================================
|
||||
|
||||
// CreateDraft создаёт новый пустой черновик для пользователя
|
||||
func (s *Service) CreateDraft(userID uuid.UUID) (*drafts.DraftInvoice, error) {
|
||||
server, err := s.accountRepo.GetActiveServer(userID)
|
||||
if err != nil || server == nil {
|
||||
return nil, errors.New("нет активного сервера")
|
||||
}
|
||||
|
||||
draft := &drafts.DraftInvoice{
|
||||
ID: uuid.New(),
|
||||
UserID: userID,
|
||||
RMSServerID: server.ID,
|
||||
Status: drafts.StatusProcessing,
|
||||
DateIncoming: func() *time.Time {
|
||||
t := time.Now()
|
||||
return &t
|
||||
}(),
|
||||
}
|
||||
|
||||
if err := s.draftRepo.Create(draft); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return draft, nil
|
||||
}
|
||||
|
||||
// GetDraftForEditor возвращает черновик для отображения в редакторе.
|
||||
// Доступен ВСЕМ ролям (Owner, Admin, Operator).
|
||||
// Проверяет только принадлежность черновика к активному серверу пользователя.
|
||||
func (s *Service) GetDraftForEditor(draftID, userID uuid.UUID) (*drafts.DraftInvoice, error) {
|
||||
draft, err := s.draftRepo.GetByID(draftID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
server, err := s.accountRepo.GetActiveServer(userID)
|
||||
if err != nil || server == nil {
|
||||
return nil, errors.New("нет активного сервера")
|
||||
}
|
||||
|
||||
if draft.RMSServerID != server.ID {
|
||||
return nil, errors.New("черновик не принадлежит активному серверу")
|
||||
}
|
||||
|
||||
return draft, nil
|
||||
}
|
||||
|
||||
// validateItemBelongsToDraft проверяет, что позиция принадлежит указанному черновику
|
||||
func (s *Service) validateItemBelongsToDraft(item *drafts.DraftInvoiceItem, draftID uuid.UUID) error {
|
||||
if item.DraftID != draftID {
|
||||
return errors.New("позиция не принадлежит указанному черновику")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateItemRawName обновляет raw_name позиции черновика.
|
||||
// Возвращает обновлённую позицию.
|
||||
func (s *Service) UpdateItemRawName(draftID, itemID uuid.UUID, newName string) (*drafts.DraftInvoiceItem, error) {
|
||||
item, err := s.draftRepo.GetItemByID(itemID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.validateItemBelongsToDraft(item, draftID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item.RawName = strings.TrimSpace(newName)
|
||||
if item.RawName == "" {
|
||||
return nil, errors.New("название позиции не может быть пустым")
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"raw_name": item.RawName,
|
||||
}
|
||||
|
||||
if err := s.draftRepo.UpdateItem(itemID, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// UpdateItemQuantity обновляет количество позиции и пересчитывает сумму.
|
||||
// Возвращает обновлённую позицию.
|
||||
func (s *Service) UpdateItemQuantity(draftID, itemID uuid.UUID, qty decimal.Decimal) (*drafts.DraftInvoiceItem, error) {
|
||||
item, err := s.draftRepo.GetItemByID(itemID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.validateItemBelongsToDraft(item, draftID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item.Quantity = qty
|
||||
s.RecalculateItemFields(item, drafts.FieldQuantity)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"quantity": item.Quantity,
|
||||
"sum": item.Sum,
|
||||
"last_edited_field1": item.LastEditedField1,
|
||||
"last_edited_field2": item.LastEditedField2,
|
||||
}
|
||||
|
||||
if err := s.draftRepo.UpdateItem(itemID, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// UpdateItemPrice обновляет цену позиции и пересчитывает сумму.
|
||||
// Возвращает обновлённую позицию.
|
||||
func (s *Service) UpdateItemPrice(draftID, itemID uuid.UUID, price decimal.Decimal) (*drafts.DraftInvoiceItem, error) {
|
||||
item, err := s.draftRepo.GetItemByID(itemID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.validateItemBelongsToDraft(item, draftID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item.Price = price
|
||||
s.RecalculateItemFields(item, drafts.FieldPrice)
|
||||
|
||||
updates := map[string]interface{}{
|
||||
"price": item.Price,
|
||||
"sum": item.Sum,
|
||||
"last_edited_field1": item.LastEditedField1,
|
||||
"last_edited_field2": item.LastEditedField2,
|
||||
}
|
||||
|
||||
if err := s.draftRepo.UpdateItem(itemID, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// SetDraftReadyToVerify переводит черновик в статус READY_TO_VERIFY.
|
||||
// Вызывается при подтверждении оператором.
|
||||
// Возвращает обновлённый черновик.
|
||||
func (s *Service) SetDraftReadyToVerify(draftID, userID uuid.UUID) (*drafts.DraftInvoice, error) {
|
||||
draft, err := s.GetDraftForEditor(draftID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if draft.Status == drafts.StatusCompleted {
|
||||
return nil, errors.New("черновик уже завершён")
|
||||
}
|
||||
|
||||
draft.Status = drafts.StatusReadyToVerify
|
||||
if err := s.draftRepo.Update(draft); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return draft, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user