expand orders #75

Merged
goc_daniel merged 3 commits from expand_orders into main 2026-04-16 14:25:59 +00:00
10 changed files with 74 additions and 10 deletions

View File

@@ -73,6 +73,11 @@ var columnMappingListOrders map[string]string = map[string]string{
"name": "b2b_customer_orders.name",
"country_id": "b2b_customer_orders.country_id",
"status": "b2b_customer_orders.status",
"base_price": "b2b_customer_orders.base_price",
"tax_incl": "b2b_customer_orders.tax_incl",
"tax_excl": "b2b_customer_orders.tax_excl",
"created_at": "b2b_customer_orders.created_at",
"updated_at": "b2b_customer_orders.updated_at",
}
func (h *OrdersHandler) PlaceNewOrder(c fiber.Ctx) error {

View File

@@ -1,5 +1,7 @@
package model
import "time"
type CustomerOrder struct {
OrderID uint `gorm:"column:order_id;primaryKey;autoIncrement" json:"order_id"`
UserID uint `gorm:"column:user_id;not null;index" json:"user_id"`
@@ -8,6 +10,11 @@ type CustomerOrder struct {
AddressString string `gorm:"column:address_string;not null" json:"address_string"`
AddressUnparsed *AddressUnparsed `gorm:"-" json:"address_unparsed"`
Status string `gorm:"column:status;size:50;not null" json:"status"`
BasePrice float64 `gorm:"column:base_price;type:decimal(10,2);not null" json:"base_price"`
TaxIncl float64 `gorm:"column:tax_incl;type:decimal(10,2);not null" json:"tax_incl"`
TaxExcl float64 `gorm:"column:tax_excl;type:decimal(10,2);not null" json:"tax_excl"`
CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"`
Products []OrderProduct `gorm:"foreignKey:OrderID;references:OrderID" json:"products"`
}

View File

@@ -1,6 +1,8 @@
package ordersRepo
import (
"time"
"git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
@@ -11,7 +13,7 @@ import (
type UIOrdersRepo interface {
UserHasOrder(user_id uint, order_id uint) (bool, error)
Find(user_id uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error)
PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string) error
PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string, base_price float64, tax_incl float64, tax_excl float64) error
ChangeOrderAddress(order_id uint, country_id uint, address_info string) error
ChangeOrderStatus(order_id uint, status string) error
}
@@ -69,7 +71,7 @@ func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersL
}, nil
}
func (repo *OrdersRepo) PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string) error {
func (repo *OrdersRepo) PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string, base_price float64, tax_incl float64, tax_excl float64) error {
order := model.CustomerOrder{
UserID: cart.UserID,
Name: name,
@@ -87,6 +89,12 @@ func (repo *OrdersRepo) PlaceNewOrder(cart *model.CustomerCart, name string, cou
})
}
order.CreatedAt = time.Now()
order.UpdatedAt = time.Now()
order.BasePrice = base_price
order.TaxIncl = tax_incl
order.TaxExcl = tax_excl
return db.DB.Create(&order).Error
}
@@ -97,6 +105,7 @@ func (repo *OrdersRepo) ChangeOrderAddress(order_id uint, country_id uint, addre
Updates(map[string]interface{}{
"country_id": country_id,
"address_string": address_info,
"updated_at": time.Now(),
}).
Error
}
@@ -105,6 +114,9 @@ func (repo *OrdersRepo) ChangeOrderStatus(order_id uint, status string) error {
return db.DB.
Table("b2b_customer_orders").
Where("order_id = ?", order_id).
Update("status", status).
Updates(map[string]interface{}{
goc_daniel marked this conversation as resolved
Review

this code is fine but just letting you know that when you use DB.Model() instead of DB.Table the updated_at columns is being updated by gorm automatically

this code is fine but just letting you know that when you use DB.Model() instead of DB.Table the updated_at columns is being updated by gorm automatically
"status": status,
"updated_at": time.Now(),
}).
Error
}

View File

@@ -130,6 +130,7 @@ func (s *AuthService) Login(req *model.LoginRequest) (*model.AuthResponse, strin
user.LangID = *req.LangID
}
user.Country = nil
goc_daniel marked this conversation as resolved
Review

db shouldn't be called in the service and updating logic should be in single place in repo. that way we don't have to rely on remembering to nullify associated models like country.

Best approach would be to build a Customer model out of a DTO for this operation for the sake of safety.
But the customer struct is small enough that nullifying Country and Role would be sufficient for now.

db shouldn't be called in the service and updating logic should be in single place in repo. that way we don't have to rely on remembering to nullify associated models like country. Best approach would be to build a Customer model out of a DTO for this operation for the sake of safety. But the customer struct is small enough that nullifying Country and Role would be sufficient for now.
Review

yeah, it's old code, and it's coauthored by me and Marek. Let's leave things as they are (and hopefully not change Customer struct anymore)

yeah, it's old code, and it's coauthored by me and Marek. Let's leave things as they are (and hopefully not change Customer struct anymore)
s.db.Save(&user)
// Generate access token (JWT)
@@ -259,6 +260,7 @@ func (s *AuthService) CompleteRegistration(req *model.CompleteRegistrationReques
user.EmailVerificationToken = ""
user.EmailVerificationExpires = nil
user.Country = nil
if err := s.db.Save(&user).Error; err != nil {
return nil, "", fmt.Errorf("failed to update user: %w", err)
}
@@ -327,6 +329,7 @@ func (s *AuthService) RequestPasswordReset(emailAddr string) error {
user.PasswordResetToken = token
user.PasswordResetExpires = &expiresAt
user.LastPasswordResetRequest = &now
user.Country = nil
if err := s.db.Save(&user).Error; err != nil {
return fmt.Errorf("failed to save reset token: %w", err)
}
@@ -381,6 +384,7 @@ func (s *AuthService) ResetPassword(token, newPassword string) error {
user.PasswordResetToken = ""
user.PasswordResetExpires = nil
user.Country = nil
if err := s.db.Save(&user).Error; err != nil {
logger.Error("password reset failed - database error",
"service", "AuthService.ResetPassword",
@@ -596,6 +600,7 @@ func (s *AuthService) UpdateJWTToken(user *model.Customer) (string, error) {
}
// Save the updated user
user.Country = nil
if err := s.db.Save(user).Error; err != nil {
return "", fmt.Errorf("database error: %w", err)
}

View File

@@ -92,6 +92,7 @@ func (s *AuthService) HandleGoogleCallback(code string) (*model.AuthResponse, st
// Update last login
now := time.Now()
user.LastLoginAt = &now
user.Country = nil
s.db.Save(user)
// Generate access token (JWT)

View File

@@ -7,8 +7,10 @@ import (
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/repos/cartsRepo"
"git.ma-al.com/goc_daniel/b2b/app/repos/ordersRepo"
"git.ma-al.com/goc_daniel/b2b/app/repos/productsRepo"
"git.ma-al.com/goc_daniel/b2b/app/service/addressesService"
"git.ma-al.com/goc_daniel/b2b/app/service/emailService"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"git.ma-al.com/goc_daniel/b2b/app/utils/logger"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
@@ -18,6 +20,7 @@ import (
type OrderService struct {
ordersRepo ordersRepo.UIOrdersRepo
cartsRepo cartsRepo.UICartsRepo
productsRepo productsRepo.UIProductsRepo
addressesService *addressesService.AddressesService
emailService *emailService.EmailService
}
@@ -26,6 +29,7 @@ func New() *OrderService {
return &OrderService{
ordersRepo: ordersRepo.New(),
cartsRepo: cartsRepo.New(),
productsRepo: productsRepo.New(),
addressesService: addressesService.New(),
emailService: emailService.NewEmailService(),
}
@@ -85,8 +89,10 @@ func (s *OrderService) PlaceNewOrder(user_id uint, cart_id uint, name string, co
name = *cart.Name
}
base_price, tax_incl, tax_excl, err := s.getOrderTotalPrice(user_id, cart_id, country_id)
// all checks passed
err = s.ordersRepo.PlaceNewOrder(cart, name, country_id, address_info)
err = s.ordersRepo.PlaceNewOrder(cart, name, country_id, address_info, base_price, tax_incl, tax_excl)
if err != nil {
return err
}
@@ -153,3 +159,27 @@ func (s *OrderService) ChangeOrderStatus(user *model.Customer, order_id uint, st
return s.ordersRepo.ChangeOrderStatus(order_id, status)
}
func (s *OrderService) getOrderTotalPrice(user_id uint, cart_id uint, country_id uint) (float64, float64, float64, error) {
cart, err := s.cartsRepo.RetrieveCart(user_id, cart_id)
if err != nil {
return 0.0, 0.0, 0.0, err
}
base_price := 0.0
tax_incl := 0.0
tax_excl := 0.0
for _, product := range cart.Products {
prices, err := s.productsRepo.GetPrice(product.ProductID, product.ProductAttributeID, constdata.SHOP_ID, user_id, country_id, product.Amount)
if err != nil {
return 0.0, 0.0, 0.0, err
}
base_price += prices.Base
tax_incl += prices.FinalTaxIncl
tax_excl += prices.FinalTaxExcl
}
return base_price, tax_incl, tax_excl, nil
}

View File

@@ -5,15 +5,14 @@ info:
http:
method: POST
url: http://localhost:3000/api/v1/public/auth/update-choice?lang_id=0&country_id=1
url: http://localhost:3000/api/v1/public/auth/update-choice?lang_id=1&country_id=1
params:
- name: lang_id
value: "0"
value: "1"
type: query
- name: country_id
value: "1"
type: query
auth: inherit
settings:
encodeUrl: true

View File

@@ -5,7 +5,7 @@ info:
http:
method: GET
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&product_attribute_id=1115&amount=1&set_amount=true
url: http://localhost:3000/api/v1/restricted/carts/add-product-to-cart?cart_id=1&product_id=51&product_attribute_id=1115&amount=2&set_amount=true
params:
- name: cart_id
value: "1"
@@ -17,7 +17,7 @@ http:
value: "1115"
type: query
- name: amount
value: "1"
value: "2"
type: query
- name: set_amount
value: "true"

View File

@@ -251,6 +251,11 @@ CREATE TABLE IF NOT EXISTS b2b_customer_orders (
country_id BIGINT UNSIGNED NOT NULL,
address_string TEXT NOT NULL,
status VARCHAR(50) NOT NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
base_price DECIMAL(10, 2) NOT NULL,
tax_incl DECIMAL(10, 2) NOT NULL,
tax_excl DECIMAL(10, 2) NOT NULL,
CONSTRAINT fk_customer_orders_customers FOREIGN KEY (user_id) REFERENCES b2b_customers(id) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT fk_customer_orders_countries FOREIGN KEY (country_id) REFERENCES b2b_countries(id) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

View File

@@ -415,7 +415,7 @@ BEGIN
LEFT JOIN ps_manufacturer m
ON m.id_manufacturer = p.id_manufacturer
LEFT JOIN ps_configuration
ON ps_configuration.name = PS_NB_DAYS_NEW_PRODUCT
ON ps_configuration.name = 'PS_NB_DAYS_NEW_PRODUCT'
WHERE p.id_product = p_id_product
LIMIT 1;