[hw-4] add postgres db

This commit is contained in:
Никита Шубин
2025-06-26 12:08:46 +00:00
parent 3ebaad5558
commit 77ed9fcf85
46 changed files with 1582 additions and 369 deletions

View File

@@ -28,15 +28,24 @@ type StockRepository interface {
StockGetByID(ctx context.Context, sku entity.Sku) (*entity.Stock, error)
}
type LomsService struct {
orders OrderRepository
stocks StockRepository
type txManager interface {
WriteWithTransaction(ctx context.Context, fn func(ctx context.Context) error) (err error)
ReadWithTransaction(ctx context.Context, fn func(ctx context.Context) error) (err error)
WriteWithRepeatableRead(ctx context.Context, fn func(ctx context.Context) error) (err error)
ReadWithRepeatableRead(ctx context.Context, fn func(ctx context.Context) error) (err error)
}
func NewLomsService(orderRepo OrderRepository, stockRepo StockRepository) *LomsService {
type LomsService struct {
orders OrderRepository
stocks StockRepository
txManager txManager
}
func NewLomsService(orderRepo OrderRepository, stockRepo StockRepository, txManager txManager) *LomsService {
return &LomsService{
orders: orderRepo,
stocks: stockRepo,
orders: orderRepo,
stocks: stockRepo,
txManager: txManager,
}
}
@@ -77,40 +86,44 @@ func (s *LomsService) OrderCreate(ctx context.Context, orderReq *pb.OrderCreateR
return int(a.ID - b.ID)
})
id, err := s.orders.OrderCreate(ctx, order)
if err != nil {
return 0, fmt.Errorf("orders.OrderCreate: %w", err)
}
var (
orderID entity.ID
resErr error
)
order.OrderID = id
commitedStocks := make([]*entity.Stock, 0, len(order.Items))
for _, item := range order.Items {
stock := &entity.Stock{
Item: item,
Reserved: item.Count,
err := s.txManager.WriteWithTransaction(ctx, func(txCtx context.Context) error {
id, err := s.orders.OrderCreate(txCtx, order)
if err != nil {
return err
}
order.OrderID = id
orderID = id
if err := s.stocks.StockReserve(ctx, stock); err != nil {
s.rollbackStocks(ctx, commitedStocks)
committed := make([]*entity.Stock, 0, len(order.Items))
for _, it := range order.Items {
st := &entity.Stock{Item: it, Reserved: it.Count}
if err := s.stocks.StockReserve(txCtx, st); err != nil {
s.rollbackStocks(txCtx, committed)
if statusErr := s.orders.OrderSetStatus(ctx, order.OrderID, pb.OrderStatus_ORDER_STATUS_FAILED.String()); statusErr != nil {
log.Error().Err(statusErr).Msg("failed to update status on stock reserve fail")
_ = s.orders.OrderSetStatus(txCtx, id,
pb.OrderStatus_ORDER_STATUS_FAILED.String())
resErr = fmt.Errorf("stocks.StockReserve: %w", err)
return nil
}
return 0, fmt.Errorf("stocks.StockReserve: %w", err)
committed = append(committed, st)
}
commitedStocks = append(commitedStocks, stock)
}
if err := s.orders.OrderSetStatus(ctx, order.OrderID, pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String()); err != nil {
s.rollbackStocks(ctx, commitedStocks)
return s.orders.OrderSetStatus(txCtx, id,
pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String())
})
if err != nil {
return 0, err
}
return order.OrderID, nil
if resErr != nil {
return 0, resErr
}
return orderID, nil
}
func (s *LomsService) OrderInfo(ctx context.Context, orderID entity.ID) (*entity.Order, error) {
@@ -122,54 +135,66 @@ func (s *LomsService) OrderInfo(ctx context.Context, orderID entity.ID) (*entity
}
func (s *LomsService) OrderPay(ctx context.Context, orderID entity.ID) error {
order, err := s.OrderInfo(ctx, orderID)
if err != nil {
return err
if orderID <= 0 {
return model.ErrInvalidInput
}
switch order.Status {
case pb.OrderStatus_ORDER_STATUS_PAYED.String():
return nil
case pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String():
for _, item := range order.Items {
if err := s.stocks.StockReserveRemove(ctx, &entity.Stock{
Item: item,
Reserved: item.Count,
}); err != nil {
log.Error().Err(err).Msg("failed to free stock reservation")
}
return s.txManager.WriteWithTransaction(ctx, func(txCtx context.Context) error {
order, err := s.orders.OrderGetByID(txCtx, orderID)
if err != nil {
return err
}
return s.orders.OrderSetStatus(ctx, orderID, pb.OrderStatus_ORDER_STATUS_PAYED.String())
default:
return model.ErrOrderInvalidStatus
}
switch order.Status {
case pb.OrderStatus_ORDER_STATUS_PAYED.String():
return nil
case pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String():
for _, it := range order.Items {
if err := s.stocks.StockReserveRemove(txCtx, &entity.Stock{
Item: it,
Reserved: it.Count,
}); err != nil {
log.Error().Err(err).Msg("failed to free stock reservation")
}
}
return s.orders.OrderSetStatus(txCtx, orderID,
pb.OrderStatus_ORDER_STATUS_PAYED.String())
default:
return model.ErrOrderInvalidStatus
}
})
}
func (s *LomsService) OrderCancel(ctx context.Context, orderID entity.ID) error {
order, err := s.OrderInfo(ctx, orderID)
if err != nil {
return err
if orderID <= 0 {
return model.ErrInvalidInput
}
switch order.Status {
case pb.OrderStatus_ORDER_STATUS_CANCELLED.String():
return nil
case pb.OrderStatus_ORDER_STATUS_FAILED.String(), pb.OrderStatus_ORDER_STATUS_PAYED.String():
return model.ErrOrderInvalidStatus
}
stocks := make([]*entity.Stock, len(order.Items))
for i, item := range order.Items {
stocks[i] = &entity.Stock{
Item: item,
Reserved: item.Count,
return s.txManager.WriteWithTransaction(ctx, func(txCtx context.Context) error {
order, err := s.orders.OrderGetByID(txCtx, orderID)
if err != nil {
return err
}
}
s.rollbackStocks(ctx, stocks)
switch order.Status {
case pb.OrderStatus_ORDER_STATUS_CANCELLED.String():
return nil
case pb.OrderStatus_ORDER_STATUS_FAILED.String(),
pb.OrderStatus_ORDER_STATUS_PAYED.String():
return model.ErrOrderInvalidStatus
}
return s.orders.OrderSetStatus(ctx, orderID, pb.OrderStatus_ORDER_STATUS_CANCELLED.String())
for _, it := range order.Items {
if err := s.stocks.StockCancel(txCtx, &entity.Stock{
Item: it,
Reserved: it.Count,
}); err != nil {
return err
}
}
return s.orders.OrderSetStatus(txCtx, orderID,
pb.OrderStatus_ORDER_STATUS_CANCELLED.String())
})
}
func (s *LomsService) StocksInfo(ctx context.Context, sku entity.Sku) (uint32, error) {
@@ -182,5 +207,5 @@ func (s *LomsService) StocksInfo(ctx context.Context, sku entity.Sku) (uint32, e
return 0, err
}
return stock.Item.Count, nil
return stock.Item.Count - stock.Reserved, nil
}