mirror of
https://github.com/3ybactuk/marketplace-go-service-project.git
synced 2025-10-30 14:03:45 +03:00
[hw-4] add postgres db
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user