package basket import ( "context" "encoding/json" "html" "strings" "golang-fave/engine/sqlw" "golang-fave/engine/utils" ) type session struct { listCurrencies map[int]*currency totalSum float64 Products map[int]*product `json:"products"` Currency *currency `json:"currency"` TotalSum string `json:"total_sum"` TotalCount int `json:"total_count"` } func (this *session) makePrice(product_price float64, product_currency_id int) float64 { if this.Currency == nil { return product_price } if this.Currency.Id == product_currency_id { return product_price } if product_currency_id == 1 { return product_price * this.Currency.Coefficient } else { if c, ok := this.listCurrencies[product_currency_id]; ok == true { return product_price / c.Coefficient } else { return product_price } } } func (this *session) updateProducts(ctx context.Context, db *sqlw.DB) { products_ids := []int{} for _, product := range this.Products { products_ids = append(products_ids, product.Id) } if len(products_ids) > 0 { if rows, err := db.Query( ctx, `SELECT fave_shop_products.id, fave_shop_products.name, fave_shop_products.price, fave_shop_products.alias, fave_shop_products.quantity, fave_shop_currencies.id, fave_shop_currencies.name, fave_shop_currencies.coefficient, fave_shop_currencies.code, fave_shop_currencies.symbol, IF(image_this.filename IS NULL, IFNULL(fave_shop_products.parent_id, fave_shop_products.id), fave_shop_products.id) as imgid, IFNULL(IFNULL(image_this.filename, image_parent.filename), '') as filename FROM fave_shop_products LEFT JOIN fave_shop_currencies ON fave_shop_currencies.id = fave_shop_products.currency LEFT JOIN ( SELECT m.product_id, m.filename FROM fave_shop_product_images as m LEFT JOIN ( SELECT t.product_id, MIN(t.ord) as ordmin FROM fave_shop_product_images as t GROUP BY t.product_id ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord WHERE u.product_id IS NOT NULL ) as image_this ON image_this.product_id = fave_shop_products.id LEFT JOIN ( SELECT m.product_id, m.filename FROM fave_shop_product_images as m LEFT JOIN ( SELECT t.product_id, MIN(t.ord) as ordmin FROM fave_shop_product_images as t GROUP BY t.product_id ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord WHERE u.product_id IS NOT NULL ) as image_parent ON image_parent.product_id = fave_shop_products.parent_id WHERE fave_shop_products.active = 1 AND fave_shop_products.id IN (`+strings.Join(utils.ArrayOfIntToArrayOfString(products_ids), ",")+`) ;`, ); err == nil { defer rows.Close() for rows.Next() { row := &utils.MySql_shop_product{} roc := &utils.MySql_shop_currency{} var img_product_id string var img_filename string if err = rows.Scan( &row.A_id, &row.A_name, &row.A_price, &row.A_alias, &row.A_quantity, &roc.A_id, &roc.A_name, &roc.A_coefficient, &roc.A_code, &roc.A_symbol, &img_product_id, &img_filename, ); err == nil { removeProductId := 0 if p, ok := this.Products[row.A_id]; ok == true { if row.A_quantity > 0 { var product_image string if img_filename == "" { product_image = utils.GetImagePlaceholderSrc() } else { product_image = "/products/images/" + img_product_id + "/thumb-0-" + img_filename } p.Name = html.EscapeString(row.A_name) p.Image = product_image p.Link = "/shop/" + row.A_alias + "/" p.price = row.A_price p.currency.Id = roc.A_id p.currency.Name = html.EscapeString(roc.A_name) p.currency.Coefficient = roc.A_coefficient p.currency.Code = html.EscapeString(roc.A_code) p.currency.Symbol = html.EscapeString(roc.A_symbol) } else { removeProductId = row.A_id } } if removeProductId != 0 { delete(this.Products, removeProductId) } } } } } } func (this *session) updateTotals(p *SBParam) { this.totalSum = 0 this.TotalCount = 0 for _, product := range this.Products { product.Price = utils.FormatProductPrice(this.makePrice(product.price, product.currency.Id), (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round) product.Sum = utils.FormatProductPrice(this.makePrice(product.price*float64(product.Quantity), product.currency.Id), (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round) this.totalSum += this.makePrice(product.price, product.currency.Id) * float64(product.Quantity) this.TotalCount += product.Quantity } this.TotalSum = utils.FormatProductPrice(this.totalSum, (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round) } func (this *session) Preload(p *SBParam) { user_currency := 1 if cookie, err := p.R.Cookie("currency"); err == nil { user_currency = utils.StrToInt(cookie.Value) } // Clear list of currencies this.listCurrencies = map[int]*currency{} // Load currencies from database if rows, err := p.DB.Query( p.R.Context(), `SELECT id, name, coefficient, code, symbol FROM fave_shop_currencies ORDER BY id ASC ;`, ); err == nil { defer rows.Close() for rows.Next() { roc := &utils.MySql_shop_currency{} if err = rows.Scan( &roc.A_id, &roc.A_name, &roc.A_coefficient, &roc.A_code, &roc.A_symbol, ); err == nil { this.listCurrencies[roc.A_id] = ¤cy{ Id: roc.A_id, Name: html.EscapeString(roc.A_name), Coefficient: roc.A_coefficient, Code: html.EscapeString(roc.A_code), Symbol: html.EscapeString(roc.A_symbol), } } } } // Check if selected currency is exists if _, ok := this.listCurrencies[user_currency]; ok != true { user_currency = 1 } // Remember selected currency if c, ok := this.listCurrencies[user_currency]; ok == true { this.Currency = ¤cy{ Id: c.Id, Name: c.Name, Coefficient: c.Coefficient, Code: c.Code, Symbol: c.Symbol, } } } func (this *session) String(p *SBParam) string { this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) json, err := json.Marshal(this) if err != nil { return `{"msg":"basket_engine_error","message":"` + err.Error() + `"}` } return string(json) } func (this *session) Plus(p *SBParam, product_id int) { if prod, ok := this.Products[product_id]; ok == true { prod.Quantity++ this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) return } row := &utils.MySql_shop_product{} roc := &utils.MySql_shop_currency{} var img_product_id string var img_filename string if err := p.DB.QueryRow( p.R.Context(), ` SELECT fave_shop_products.id, fave_shop_products.name, fave_shop_products.price, fave_shop_products.alias, fave_shop_currencies.id, fave_shop_currencies.name, fave_shop_currencies.coefficient, fave_shop_currencies.code, fave_shop_currencies.symbol, IF(image_this.filename IS NULL, IFNULL(fave_shop_products.parent_id, fave_shop_products.id), fave_shop_products.id) as imgid, IFNULL(IFNULL(image_this.filename, image_parent.filename), '') as filename FROM fave_shop_products LEFT JOIN fave_shop_currencies ON fave_shop_currencies.id = fave_shop_products.currency LEFT JOIN ( SELECT m.product_id, m.filename FROM fave_shop_product_images as m LEFT JOIN ( SELECT t.product_id, MIN(t.ord) as ordmin FROM fave_shop_product_images as t GROUP BY t.product_id ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord WHERE u.product_id IS NOT NULL ) as image_this ON image_this.product_id = fave_shop_products.id LEFT JOIN ( SELECT m.product_id, m.filename FROM fave_shop_product_images as m LEFT JOIN ( SELECT t.product_id, MIN(t.ord) as ordmin FROM fave_shop_product_images as t GROUP BY t.product_id ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord WHERE u.product_id IS NOT NULL ) as image_parent ON image_parent.product_id = fave_shop_products.parent_id WHERE fave_shop_products.active = 1 AND fave_shop_products.quantity > 0 AND fave_shop_products.id = ? LIMIT 1;`, product_id, ).Scan( &row.A_id, &row.A_name, &row.A_price, &row.A_alias, &roc.A_id, &roc.A_name, &roc.A_coefficient, &roc.A_code, &roc.A_symbol, &img_product_id, &img_filename, ); err == nil { var product_image string if img_filename == "" { product_image = utils.GetImagePlaceholderSrc() } else { product_image = "/products/images/" + img_product_id + "/thumb-0-" + img_filename } this.Products[product_id] = &product{ currency: ¤cy{Id: roc.A_id, Name: roc.A_name, Coefficient: roc.A_coefficient, Code: roc.A_code, Symbol: roc.A_symbol}, Id: row.A_id, Name: html.EscapeString(row.A_name), Image: product_image, Link: "/shop/" + row.A_alias + "/", price: row.A_price, Quantity: 1, } this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) } } func (this *session) Minus(p *SBParam, product_id int) { if prod, ok := this.Products[product_id]; ok == true { if prod.Quantity > 1 { prod.Quantity-- } else { delete(this.Products, product_id) } this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) } } func (this *session) Remove(p *SBParam, product_id int) { if _, ok := this.Products[product_id]; ok == true { delete(this.Products, product_id) this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) } } func (this *session) ClearBasket(p *SBParam) { this.Products = map[int]*product{} this.updateProducts(p.R.Context(), p.DB) this.updateTotals(p) } func (this *session) ProductsCount() int { return this.TotalCount } func (this *session) GetAll(p *SBParam) *utils.MySql_basket { products := []utils.MySql_basket_product{} for _, product := range this.Products { products = append(products, utils.MySql_basket_product{ A_product_id: product.Id, A_price: this.makePrice(product.price, product.currency.Id), A_quantity: product.Quantity, RenderName: product.Name, RenderLink: product.Link, RenderPrice: product.Price, RenderQuantity: product.Quantity, RenderSum: product.Sum, }) } currency := utils.MySql_basket_currency{ Id: this.Currency.Id, Name: this.Currency.Name, Coefficient: this.Currency.Coefficient, Code: this.Currency.Code, Symbol: this.Currency.Symbol, } all := utils.MySql_basket{ Products: &products, Currency: ¤cy, TotalSum: this.totalSum, TotalCount: this.TotalCount, RenderTotalSum: this.TotalSum, } return &all }