diff --git a/app/delivery/web/api/restricted/addresses.go b/app/delivery/web/api/restricted/addresses.go index 903f011..f33b7cb 100644 --- a/app/delivery/web/api/restricted/addresses.go +++ b/app/delivery/web/api/restricted/addresses.go @@ -124,13 +124,13 @@ func (h *AddressesHandler) RetrieveAddressesInfo(c fiber.Ctx) error { JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) } - addresses_info, err := h.addressesService.RetrieveAddressesInfo(userID) + addresses, err := h.addressesService.RetrieveAddresses(userID) if err != nil { return c.Status(responseErrors.GetErrorStatus(err)). JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err))) } - return c.JSON(response.Make(&addresses_info, 0, i18n.T_(c, response.Message_OK))) + return c.JSON(response.Make(addresses, 0, i18n.T_(c, response.Message_OK))) } func (h *AddressesHandler) DeleteAddress(c fiber.Ctx) error { diff --git a/app/delivery/web/api/restricted/orders.go b/app/delivery/web/api/restricted/orders.go index 0d0ef51..34fb2c5 100644 --- a/app/delivery/web/api/restricted/orders.go +++ b/app/delivery/web/api/restricted/orders.go @@ -29,7 +29,7 @@ func OrdersHandlerRoutes(r fiber.Router) fiber.Router { handler := NewOrdersHandler() r.Get("/list", handler.ListOrders) - r.Get("/place-new-order", handler.PlaceNewOrder) + r.Post("/place-new-order", handler.PlaceNewOrder) r.Get("/change-order-address", handler.ChangeOrderAddress) r.Get("/change-order-status", handler.ChangeOrderStatus) @@ -82,7 +82,6 @@ func (h *OrdersHandler) PlaceNewOrder(c fiber.Ctx) error { JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) } - address_info := c.Query("address_info") country_id_attribute := c.Query("country_id") country_id, err := strconv.Atoi(country_id_attribute) if err != nil { @@ -90,6 +89,12 @@ func (h *OrdersHandler) PlaceNewOrder(c fiber.Ctx) error { JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) } + address_info := string(c.Body()) + if address_info == "" { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)). + JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) + } + name := c.Query("name") err = h.ordersService.PlaceNewOrder(userID, uint(cart_id), name, uint(country_id), address_info) @@ -116,7 +121,6 @@ func (h *OrdersHandler) ChangeOrderAddress(c fiber.Ctx) error { JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) } - address_info := c.Query("address_info") country_id_attribute := c.Query("country_id") country_id, err := strconv.Atoi(country_id_attribute) if err != nil { @@ -124,6 +128,12 @@ func (h *OrdersHandler) ChangeOrderAddress(c fiber.Ctx) error { JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) } + address_info := string(c.Body()) + if address_info == "" { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)). + JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) + } + err = h.ordersService.ChangeOrderAddress(user, uint(order_id), uint(country_id), address_info) if err != nil { return c.Status(responseErrors.GetErrorStatus(err)). diff --git a/app/model/address.go b/app/model/address.go index a84056a..96efaa8 100644 --- a/app/model/address.go +++ b/app/model/address.go @@ -1,25 +1,18 @@ package model type Address struct { - ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` - CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"` - AddressInfo string `gorm:"column:address_info;not null" json:"address_info"` - CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"` + ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"` + AddressString string `gorm:"column:address_string;not null" json:"address_string"` + AddressUnparsed *AddressUnparsed `gorm:"-" json:"address_unparsed"` + CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"` } func (Address) TableName() string { return "b2b_addresses" } -type AddressUnparsed struct { - ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` - CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"` - AddressInfo AddressField `gorm:"column:address_info;not null" json:"address_info"` - CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"` -} - -type AddressField interface { -} +type AddressUnparsed interface{} // Address template in Poland type AddressPL struct { diff --git a/app/model/order.go b/app/model/order.go index 8fcb9b6..a6556b2 100644 --- a/app/model/order.go +++ b/app/model/order.go @@ -1,13 +1,14 @@ package model 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"` - Name string `gorm:"column:name;not null" json:"name"` - CountryID uint `gorm:"column:country_id;not null" json:"country_id"` - AddressJSON string `gorm:"column:address_json;not null" json:"address_json"` - Status string `gorm:"column:status;size:50;not null" json:"status"` - Products []OrderProduct `gorm:"foreignKey:OrderID;references:ID" json:"products"` + OrderID uint `gorm:"column:order_id;primaryKey;autoIncrement" json:"order_id"` + UserID uint `gorm:"column:user_id;not null;index" json:"user_id"` + Name string `gorm:"column:name;not null" json:"name"` + CountryID uint `gorm:"column:country_id;not null" json:"country_id"` + 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"` + Products []OrderProduct `gorm:"foreignKey:OrderID;references:OrderID" json:"products"` } func (CustomerOrder) TableName() string { diff --git a/app/repos/addressesRepo/addressesRepo.go b/app/repos/addressesRepo/addressesRepo.go index 5f674a0..ce6437d 100644 --- a/app/repos/addressesRepo/addressesRepo.go +++ b/app/repos/addressesRepo/addressesRepo.go @@ -48,9 +48,9 @@ func (repo *AddressesRepo) UserAddressesAmt(user_id uint) (uint, error) { func (repo *AddressesRepo) AddNewAddress(user_id uint, address_info string, country_id uint) error { address := model.Address{ - CustomerID: user_id, - AddressInfo: address_info, - CountryID: country_id, + CustomerID: user_id, + AddressString: address_info, + CountryID: country_id, } return db.DB. @@ -60,10 +60,10 @@ func (repo *AddressesRepo) AddNewAddress(user_id uint, address_info string, coun func (repo *AddressesRepo) UpdateAddress(user_id uint, address_id uint, address_info string, country_id uint) error { address := model.Address{ - ID: address_id, - CustomerID: user_id, - AddressInfo: address_info, - CountryID: country_id, + ID: address_id, + CustomerID: user_id, + AddressString: address_info, + CountryID: country_id, } return db.DB. diff --git a/app/repos/ordersRepo/ordersRepo.go b/app/repos/ordersRepo/ordersRepo.go index a530293..c3b8158 100644 --- a/app/repos/ordersRepo/ordersRepo.go +++ b/app/repos/ordersRepo/ordersRepo.go @@ -10,7 +10,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) + 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 ChangeOrderAddress(order_id uint, country_id uint, address_info string) error ChangeOrderStatus(order_id uint, status string) error @@ -35,14 +35,14 @@ func (repo *OrdersRepo) UserHasOrder(user_id uint, order_id uint) (bool, error) return amt >= 1, err } -func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.CustomerOrder], error) { +func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error) { var list []model.CustomerOrder var total int64 query := db.Get(). Model(&model.CustomerOrder{}). Preload("Products"). - Order("b2b_customer_orders.id DESC") + Order("b2b_customer_orders.order_id DESC") // Apply all filters if filt != nil { @@ -52,7 +52,7 @@ func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersL // run counter first as query is without limit and offset err := query.Count(&total).Error if err != nil { - return find.Found[model.CustomerOrder]{}, err + return &find.Found[model.CustomerOrder]{}, err } err = query. @@ -60,10 +60,10 @@ func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersL Offset(p.Offset()). Find(&list).Error if err != nil { - return find.Found[model.CustomerOrder]{}, err + return &find.Found[model.CustomerOrder]{}, err } - return find.Found[model.CustomerOrder]{ + return &find.Found[model.CustomerOrder]{ Items: list, Count: uint(total), }, nil @@ -71,12 +71,12 @@ func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersL func (repo *OrdersRepo) PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string) error { order := model.CustomerOrder{ - UserID: cart.UserID, - Name: name, - CountryID: country_id, - AddressJSON: address_info, - Status: constdata.NEW_ORDER_STATUS, - Products: make([]model.OrderProduct, 0, len(cart.Products)), + UserID: cart.UserID, + Name: name, + CountryID: country_id, + AddressString: address_info, + Status: constdata.NEW_ORDER_STATUS, + Products: make([]model.OrderProduct, 0, len(cart.Products)), } for _, product := range cart.Products { @@ -95,8 +95,8 @@ func (repo *OrdersRepo) ChangeOrderAddress(order_id uint, country_id uint, addre Table("b2b_customer_orders"). Where("order_id = ?", order_id). Updates(map[string]interface{}{ - "country_id": country_id, - "address_info": address_info, + "country_id": country_id, + "address_string": address_info, }). Error } diff --git a/app/service/addressesService/addressesService.go b/app/service/addressesService/addressesService.go index 48eadc3..0b7a820 100644 --- a/app/service/addressesService/addressesService.go +++ b/app/service/addressesService/addressesService.go @@ -21,7 +21,7 @@ func New() *AddressesService { } } -func (s *AddressesService) GetTemplate(country_id uint) (model.AddressField, error) { +func (s *AddressesService) GetTemplate(country_id uint) (model.AddressUnparsed, error) { switch country_id { case 1: // Poland @@ -74,30 +74,23 @@ func (s *AddressesService) ModifyAddress(user_id uint, address_id uint, address_ return s.repo.UpdateAddress(user_id, address_id, address_info, country_id) } -func (s *AddressesService) RetrieveAddressesInfo(user_id uint) (*[]model.AddressUnparsed, error) { - parsed_addresses, err := s.repo.RetrieveAddresses(user_id) +func (s *AddressesService) RetrieveAddresses(user_id uint) (*[]model.Address, error) { + addresses, err := s.repo.RetrieveAddresses(user_id) if err != nil { return nil, err } - var unparsed_addresses []model.AddressUnparsed - - for i := 0; i < len(*parsed_addresses); i++ { - var next_address model.AddressUnparsed - next_address.ID = (*parsed_addresses)[i].ID - next_address.CustomerID = (*parsed_addresses)[i].CustomerID - next_address.CountryID = (*parsed_addresses)[i].CountryID - - next_address.AddressInfo, err = s.ValidateAddressJson((*parsed_addresses)[i].AddressInfo, next_address.CountryID) + for i := 0; i < len(*addresses); i++ { + address_unparsed, err := s.ValidateAddressJson((*addresses)[i].AddressString, (*addresses)[i].CountryID) // log such errors if err != nil { fmt.Printf("err: %v\n", err) } - unparsed_addresses = append(unparsed_addresses, next_address) + (*addresses)[i].AddressUnparsed = &address_unparsed } - return &unparsed_addresses, nil + return addresses, nil } func (s *AddressesService) DeleteAddress(user_id uint, address_id uint) error { @@ -112,7 +105,7 @@ func (s *AddressesService) DeleteAddress(user_id uint, address_id uint) error { } // validateAddressJson makes sure that the info string represents a valid json of address in given country -func (s *AddressesService) ValidateAddressJson(info string, country_id uint) (model.AddressField, error) { +func (s *AddressesService) ValidateAddressJson(info string, country_id uint) (model.AddressUnparsed, error) { dec := json.NewDecoder(strings.NewReader(info)) dec.DisallowUnknownFields() diff --git a/app/service/orderService/orderService.go b/app/service/orderService/orderService.go index 397f226..9d831e5 100644 --- a/app/service/orderService/orderService.go +++ b/app/service/orderService/orderService.go @@ -1,6 +1,7 @@ package orderService import ( + "fmt" "strconv" "git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms" @@ -27,14 +28,29 @@ func New() *OrderService { } } -func (s *OrderService) Find(user *model.Customer, p find.Paging, filt *filters.FiltersList) (find.Found[model.CustomerOrder], error) { +func (s *OrderService) Find(user *model.Customer, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error) { if !user.HasPermission(perms.ViewAllOrders) { // append filter to view only this user's orders idStr := strconv.FormatUint(uint64(user.ID), 10) filt.Append(filters.Where("b2b_customer_orders.user_id = " + idStr)) } - return s.ordersRepo.Find(user.ID, p, filt) + list, err := s.ordersRepo.Find(user.ID, p, filt) + if err != nil { + return nil, err + } + + for i := 0; i < len(list.Items); i++ { + address_unparsed, err := s.addressesService.ValidateAddressJson(list.Items[i].AddressString, list.Items[i].CountryID) + // log such errors + if err != nil { + fmt.Printf("err: %v\n", err) + } + + list.Items[i].AddressUnparsed = &address_unparsed + } + + return list, nil } func (s *OrderService) PlaceNewOrder(user_id uint, cart_id uint, name string, country_id uint, address_info string) error { diff --git a/bruno/b2b_daniel/carts/retrieve-cart.yml b/bruno/b2b_daniel/carts/retrieve-cart.yml index 69c5e2e..809b524 100644 --- a/bruno/b2b_daniel/carts/retrieve-cart.yml +++ b/bruno/b2b_daniel/carts/retrieve-cart.yml @@ -5,10 +5,10 @@ info: http: method: GET - url: http://localhost:3000/api/v1/restricted/carts/retrieve-cart?cart_id=3 + url: http://localhost:3000/api/v1/restricted/carts/retrieve-cart?cart_id=1 params: - name: cart_id - value: "3" + value: "1" type: query auth: inherit diff --git a/bruno/b2b_daniel/orders/change-order-address.yml b/bruno/b2b_daniel/orders/change-order-address.yml new file mode 100644 index 0000000..e6d8856 --- /dev/null +++ b/bruno/b2b_daniel/orders/change-order-address.yml @@ -0,0 +1,33 @@ +info: + name: change-order-address + type: http + seq: 3 + +http: + method: GET + url: http://localhost:3000/api/v1/restricted/orders/change-order-address?order_id=1&country_id=1 + params: + - name: order_id + value: "1" + type: query + - name: country_id + value: "1" + type: query + body: + type: json + data: |- + { + "postal_code": "31-154", + "city": "Kraków", + "voivodeship": "śląskie", + "street": "Długa", + "building_no": "5", + "recipient": "Adam Adamowicz" + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/bruno/b2b_daniel/orders/change-order-status.yml b/bruno/b2b_daniel/orders/change-order-status.yml new file mode 100644 index 0000000..78c0e74 --- /dev/null +++ b/bruno/b2b_daniel/orders/change-order-status.yml @@ -0,0 +1,22 @@ +info: + name: change-order-status + type: http + seq: 4 + +http: + method: GET + url: http://localhost:3000/api/v1/restricted/orders/change-order-status?order_id=1&status=PAID + params: + - name: order_id + value: "1" + type: query + - name: status + value: PAID + type: query + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/bruno/b2b_daniel/orders/folder.yml b/bruno/b2b_daniel/orders/folder.yml new file mode 100644 index 0000000..f542e59 --- /dev/null +++ b/bruno/b2b_daniel/orders/folder.yml @@ -0,0 +1,7 @@ +info: + name: orders + type: folder + seq: 11 + +request: + auth: inherit diff --git a/bruno/b2b_daniel/orders/list.yml b/bruno/b2b_daniel/orders/list.yml new file mode 100644 index 0000000..ce7e339 --- /dev/null +++ b/bruno/b2b_daniel/orders/list.yml @@ -0,0 +1,31 @@ +info: + name: list + type: http + seq: 2 + +http: + method: GET + url: http://localhost:3000/api/v1/restricted/orders/list?p=1&elems=30&sort=product_id,asc&user_id=2&name=~sdj + params: + - name: p + value: "1" + type: query + - name: elems + value: "30" + type: query + - name: sort + value: product_id,asc + type: query + - name: user_id + value: "2" + type: query + - name: name + value: ~sdj + type: query + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/bruno/b2b_daniel/orders/place-new-order.yml b/bruno/b2b_daniel/orders/place-new-order.yml new file mode 100644 index 0000000..80ef063 --- /dev/null +++ b/bruno/b2b_daniel/orders/place-new-order.yml @@ -0,0 +1,37 @@ +info: + name: place-new-order + type: http + seq: 1 + +http: + method: POST + url: http://localhost:3000/api/v1/restricted/orders/place-new-order?cart_id=1&name=sdjalksd&country_id=1 + params: + - name: cart_id + value: "1" + type: query + - name: name + value: sdjalksd + type: query + - name: country_id + value: "1" + type: query + body: + type: json + data: |- + { + "postal_code": "31-154", + "city": "Kraków", + "voivodeship": "małopolskie", + "street": "Długa", + "building_no": "5", + "apartment_no": "7", + "recipient": "Jan Kowalski" + } + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/i18n/migrations/20260302163122_create_tables.sql b/i18n/migrations/20260302163122_create_tables.sql index 8c1cf30..a2dcdbe 100644 --- a/i18n/migrations/20260302163122_create_tables.sql +++ b/i18n/migrations/20260302163122_create_tables.sql @@ -151,34 +151,6 @@ CREATE TABLE IF NOT EXISTS b2b_carts_products ( CREATE INDEX IF NOT EXISTS idx_carts_products_cart_id ON b2b_carts_products (cart_id); --- customer_orders -CREATE TABLE IF NOT EXISTS b2b_customer_orders ( - order_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, - user_id BIGINT UNSIGNED NOT NULL, - name TEXT NOT NULL, - country_id BIGINT UNSIGNED NOT NULL, - address_json TEXT NOT NULL, - status VARCHAR(50) 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; -CREATE INDEX idx_customer_orders_user_id ON b2b_customer_orders (user_id); -CREATE INDEX idx_customer_orders_country_id ON b2b_customer_orders (country_id); - - --- orders_products -CREATE TABLE IF NOT EXISTS b2b_orders_products ( - id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, - order_id BIGINT UNSIGNED NOT NULL, - product_id INT UNSIGNED NOT NULL, - product_attribute_id INT NULL, - amount INT UNSIGNED NOT NULL, - CONSTRAINT fk_orders_products_customer_orders FOREIGN KEY (order_id) REFERENCES b2b_customer_orders (id) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT fk_orders_products_product FOREIGN KEY (product_id) REFERENCES ps_product (id_product) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; -CREATE INDEX IF NOT EXISTS idx_orders_products_order_id ON b2b_orders_products (order_id); - - -- favorites CREATE TABLE IF NOT EXISTS b2b_favorites ( user_id BIGINT UNSIGNED NOT NULL, @@ -252,7 +224,7 @@ ON `b2b_countries` ( CREATE TABLE IF NOT EXISTS b2b_addresses ( id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, b2b_customer_id BIGINT UNSIGNED NOT NULL, - address_info TEXT NOT NULL, + address_string TEXT NOT NULL, b2b_country_id BIGINT UNSIGNED NOT NULL, PRIMARY KEY (id), CONSTRAINT fk_b2b_addresses_b2b_customers FOREIGN KEY (b2b_customer_id) REFERENCES b2b_customers (id) ON DELETE CASCADE ON UPDATE CASCADE, @@ -260,6 +232,34 @@ CREATE TABLE IF NOT EXISTS b2b_addresses ( ) ENGINE = InnoDB; +-- customer_orders +CREATE TABLE IF NOT EXISTS b2b_customer_orders ( + order_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT UNSIGNED NOT NULL, + name TEXT NOT NULL, + country_id BIGINT UNSIGNED NOT NULL, + address_string TEXT NOT NULL, + status VARCHAR(50) 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; +CREATE INDEX idx_customer_orders_user_id ON b2b_customer_orders (user_id); +CREATE INDEX idx_customer_orders_country_id ON b2b_customer_orders (country_id); + + +-- orders_products +CREATE TABLE IF NOT EXISTS b2b_orders_products ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + order_id BIGINT UNSIGNED NOT NULL, + product_id INT UNSIGNED NOT NULL, + product_attribute_id INT NULL, + amount INT UNSIGNED NOT NULL, + CONSTRAINT fk_orders_products_customer_orders FOREIGN KEY (order_id) REFERENCES b2b_customer_orders (order_id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT fk_orders_products_product FOREIGN KEY (product_id) REFERENCES ps_product (id_product) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; +CREATE INDEX IF NOT EXISTS idx_orders_products_order_id ON b2b_orders_products (order_id); + + CREATE TABLE b2b_specific_price ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL,