session.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package basket
  2. import (
  3. "context"
  4. "encoding/json"
  5. "html"
  6. "strings"
  7. "golang-fave/engine/sqlw"
  8. "golang-fave/engine/utils"
  9. )
  10. type session struct {
  11. listCurrencies map[int]*currency
  12. totalSum float64
  13. Products map[int]*product `json:"products"`
  14. Currency *currency `json:"currency"`
  15. TotalSum string `json:"total_sum"`
  16. TotalCount int `json:"total_count"`
  17. }
  18. func (this *session) makePrice(product_price float64, product_currency_id int) float64 {
  19. if this.Currency == nil {
  20. return product_price
  21. }
  22. if this.Currency.Id == product_currency_id {
  23. return product_price
  24. }
  25. if product_currency_id == 1 {
  26. return product_price * this.Currency.Coefficient
  27. } else {
  28. if c, ok := this.listCurrencies[product_currency_id]; ok == true {
  29. return product_price / c.Coefficient
  30. } else {
  31. return product_price
  32. }
  33. }
  34. }
  35. func (this *session) updateProducts(ctx context.Context, db *sqlw.DB) {
  36. products_ids := []int{}
  37. for _, product := range this.Products {
  38. products_ids = append(products_ids, product.Id)
  39. }
  40. if len(products_ids) > 0 {
  41. if rows, err := db.Query(
  42. ctx,
  43. `SELECT
  44. fave_shop_products.id,
  45. fave_shop_products.name,
  46. fave_shop_products.price,
  47. fave_shop_products.alias,
  48. fave_shop_products.quantity,
  49. fave_shop_currencies.id,
  50. fave_shop_currencies.name,
  51. fave_shop_currencies.coefficient,
  52. fave_shop_currencies.code,
  53. fave_shop_currencies.symbol,
  54. IF(image_this.filename IS NULL, IFNULL(fave_shop_products.parent_id, fave_shop_products.id), fave_shop_products.id) as imgid,
  55. IFNULL(IFNULL(image_this.filename, image_parent.filename), '') as filename
  56. FROM
  57. fave_shop_products
  58. LEFT JOIN fave_shop_currencies ON fave_shop_currencies.id = fave_shop_products.currency
  59. LEFT JOIN (
  60. SELECT
  61. m.product_id,
  62. m.filename
  63. FROM
  64. fave_shop_product_images as m
  65. LEFT JOIN (
  66. SELECT
  67. t.product_id,
  68. MIN(t.ord) as ordmin
  69. FROM
  70. fave_shop_product_images as t
  71. GROUP BY
  72. t.product_id
  73. ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord
  74. WHERE
  75. u.product_id IS NOT NULL
  76. ) as image_this ON image_this.product_id = fave_shop_products.id
  77. LEFT JOIN (
  78. SELECT
  79. m.product_id,
  80. m.filename
  81. FROM
  82. fave_shop_product_images as m
  83. LEFT JOIN (
  84. SELECT
  85. t.product_id,
  86. MIN(t.ord) as ordmin
  87. FROM
  88. fave_shop_product_images as t
  89. GROUP BY
  90. t.product_id
  91. ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord
  92. WHERE
  93. u.product_id IS NOT NULL
  94. ) as image_parent ON image_parent.product_id = fave_shop_products.parent_id
  95. WHERE
  96. fave_shop_products.active = 1 AND
  97. fave_shop_products.id IN (`+strings.Join(utils.ArrayOfIntToArrayOfString(products_ids), ",")+`)
  98. ;`,
  99. ); err == nil {
  100. defer rows.Close()
  101. for rows.Next() {
  102. row := &utils.MySql_shop_product{}
  103. roc := &utils.MySql_shop_currency{}
  104. var img_product_id string
  105. var img_filename string
  106. if err = rows.Scan(
  107. &row.A_id,
  108. &row.A_name,
  109. &row.A_price,
  110. &row.A_alias,
  111. &row.A_quantity,
  112. &roc.A_id,
  113. &roc.A_name,
  114. &roc.A_coefficient,
  115. &roc.A_code,
  116. &roc.A_symbol,
  117. &img_product_id,
  118. &img_filename,
  119. ); err == nil {
  120. removeProductId := 0
  121. if p, ok := this.Products[row.A_id]; ok == true {
  122. if row.A_quantity > 0 {
  123. var product_image string
  124. if img_filename == "" {
  125. product_image = utils.GetImagePlaceholderSrc()
  126. } else {
  127. product_image = "/products/images/" + img_product_id + "/thumb-0-" + img_filename
  128. }
  129. p.Name = html.EscapeString(row.A_name)
  130. p.Image = product_image
  131. p.Link = "/shop/" + row.A_alias + "/"
  132. p.price = row.A_price
  133. p.currency.Id = roc.A_id
  134. p.currency.Name = html.EscapeString(roc.A_name)
  135. p.currency.Coefficient = roc.A_coefficient
  136. p.currency.Code = html.EscapeString(roc.A_code)
  137. p.currency.Symbol = html.EscapeString(roc.A_symbol)
  138. } else {
  139. removeProductId = row.A_id
  140. }
  141. }
  142. if removeProductId != 0 {
  143. delete(this.Products, removeProductId)
  144. }
  145. }
  146. }
  147. }
  148. }
  149. }
  150. func (this *session) updateTotals(p *SBParam) {
  151. this.totalSum = 0
  152. this.TotalCount = 0
  153. for _, product := range this.Products {
  154. product.Price = utils.FormatProductPrice(this.makePrice(product.price, product.currency.Id), (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round)
  155. product.Sum = utils.FormatProductPrice(this.makePrice(product.price*float64(product.Quantity), product.currency.Id), (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round)
  156. this.totalSum += this.makePrice(product.price, product.currency.Id) * float64(product.Quantity)
  157. this.TotalCount += product.Quantity
  158. }
  159. this.TotalSum = utils.FormatProductPrice(this.totalSum, (*p.Config).Shop.Price.Format, (*p.Config).Shop.Price.Round)
  160. }
  161. func (this *session) Preload(p *SBParam) {
  162. user_currency := 1
  163. if cookie, err := p.R.Cookie("currency"); err == nil {
  164. user_currency = utils.StrToInt(cookie.Value)
  165. }
  166. // Clear list of currencies
  167. this.listCurrencies = map[int]*currency{}
  168. // Load currencies from database
  169. if rows, err := p.DB.Query(
  170. p.R.Context(),
  171. `SELECT
  172. id,
  173. name,
  174. coefficient,
  175. code,
  176. symbol
  177. FROM
  178. fave_shop_currencies
  179. ORDER BY
  180. id ASC
  181. ;`,
  182. ); err == nil {
  183. defer rows.Close()
  184. for rows.Next() {
  185. roc := &utils.MySql_shop_currency{}
  186. if err = rows.Scan(
  187. &roc.A_id,
  188. &roc.A_name,
  189. &roc.A_coefficient,
  190. &roc.A_code,
  191. &roc.A_symbol,
  192. ); err == nil {
  193. this.listCurrencies[roc.A_id] = &currency{
  194. Id: roc.A_id,
  195. Name: html.EscapeString(roc.A_name),
  196. Coefficient: roc.A_coefficient,
  197. Code: html.EscapeString(roc.A_code),
  198. Symbol: html.EscapeString(roc.A_symbol),
  199. }
  200. }
  201. }
  202. }
  203. // Check if selected currency is exists
  204. if _, ok := this.listCurrencies[user_currency]; ok != true {
  205. user_currency = 1
  206. }
  207. // Remember selected currency
  208. if c, ok := this.listCurrencies[user_currency]; ok == true {
  209. this.Currency = &currency{
  210. Id: c.Id,
  211. Name: c.Name,
  212. Coefficient: c.Coefficient,
  213. Code: c.Code,
  214. Symbol: c.Symbol,
  215. }
  216. }
  217. }
  218. func (this *session) String(p *SBParam) string {
  219. this.updateProducts(p.R.Context(), p.DB)
  220. this.updateTotals(p)
  221. json, err := json.Marshal(this)
  222. if err != nil {
  223. return `{"msg":"basket_engine_error","message":"` + err.Error() + `"}`
  224. }
  225. return string(json)
  226. }
  227. func (this *session) Plus(p *SBParam, product_id int) {
  228. if prod, ok := this.Products[product_id]; ok == true {
  229. prod.Quantity++
  230. this.updateProducts(p.R.Context(), p.DB)
  231. this.updateTotals(p)
  232. return
  233. }
  234. row := &utils.MySql_shop_product{}
  235. roc := &utils.MySql_shop_currency{}
  236. var img_product_id string
  237. var img_filename string
  238. if err := p.DB.QueryRow(
  239. p.R.Context(),
  240. `
  241. SELECT
  242. fave_shop_products.id,
  243. fave_shop_products.name,
  244. fave_shop_products.price,
  245. fave_shop_products.alias,
  246. fave_shop_currencies.id,
  247. fave_shop_currencies.name,
  248. fave_shop_currencies.coefficient,
  249. fave_shop_currencies.code,
  250. fave_shop_currencies.symbol,
  251. IF(image_this.filename IS NULL, IFNULL(fave_shop_products.parent_id, fave_shop_products.id), fave_shop_products.id) as imgid,
  252. IFNULL(IFNULL(image_this.filename, image_parent.filename), '') as filename
  253. FROM
  254. fave_shop_products
  255. LEFT JOIN fave_shop_currencies ON fave_shop_currencies.id = fave_shop_products.currency
  256. LEFT JOIN (
  257. SELECT
  258. m.product_id,
  259. m.filename
  260. FROM
  261. fave_shop_product_images as m
  262. LEFT JOIN (
  263. SELECT
  264. t.product_id,
  265. MIN(t.ord) as ordmin
  266. FROM
  267. fave_shop_product_images as t
  268. GROUP BY
  269. t.product_id
  270. ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord
  271. WHERE
  272. u.product_id IS NOT NULL
  273. ) as image_this ON image_this.product_id = fave_shop_products.id
  274. LEFT JOIN (
  275. SELECT
  276. m.product_id,
  277. m.filename
  278. FROM
  279. fave_shop_product_images as m
  280. LEFT JOIN (
  281. SELECT
  282. t.product_id,
  283. MIN(t.ord) as ordmin
  284. FROM
  285. fave_shop_product_images as t
  286. GROUP BY
  287. t.product_id
  288. ) as u ON u.product_id = m.product_id AND u.ordmin = m.ord
  289. WHERE
  290. u.product_id IS NOT NULL
  291. ) as image_parent ON image_parent.product_id = fave_shop_products.parent_id
  292. WHERE
  293. fave_shop_products.active = 1 AND
  294. fave_shop_products.quantity > 0 AND
  295. fave_shop_products.id = ?
  296. LIMIT 1;`,
  297. product_id,
  298. ).Scan(
  299. &row.A_id,
  300. &row.A_name,
  301. &row.A_price,
  302. &row.A_alias,
  303. &roc.A_id,
  304. &roc.A_name,
  305. &roc.A_coefficient,
  306. &roc.A_code,
  307. &roc.A_symbol,
  308. &img_product_id,
  309. &img_filename,
  310. ); err == nil {
  311. var product_image string
  312. if img_filename == "" {
  313. product_image = utils.GetImagePlaceholderSrc()
  314. } else {
  315. product_image = "/products/images/" + img_product_id + "/thumb-0-" + img_filename
  316. }
  317. this.Products[product_id] = &product{
  318. currency: &currency{Id: roc.A_id, Name: roc.A_name, Coefficient: roc.A_coefficient, Code: roc.A_code, Symbol: roc.A_symbol},
  319. Id: row.A_id,
  320. Name: html.EscapeString(row.A_name),
  321. Image: product_image,
  322. Link: "/shop/" + row.A_alias + "/",
  323. price: row.A_price,
  324. Quantity: 1,
  325. }
  326. this.updateProducts(p.R.Context(), p.DB)
  327. this.updateTotals(p)
  328. }
  329. }
  330. func (this *session) Minus(p *SBParam, product_id int) {
  331. if prod, ok := this.Products[product_id]; ok == true {
  332. if prod.Quantity > 1 {
  333. prod.Quantity--
  334. } else {
  335. delete(this.Products, product_id)
  336. }
  337. this.updateProducts(p.R.Context(), p.DB)
  338. this.updateTotals(p)
  339. }
  340. }
  341. func (this *session) Remove(p *SBParam, product_id int) {
  342. if _, ok := this.Products[product_id]; ok == true {
  343. delete(this.Products, product_id)
  344. this.updateProducts(p.R.Context(), p.DB)
  345. this.updateTotals(p)
  346. }
  347. }
  348. func (this *session) ClearBasket(p *SBParam) {
  349. this.Products = map[int]*product{}
  350. this.updateProducts(p.R.Context(), p.DB)
  351. this.updateTotals(p)
  352. }
  353. func (this *session) ProductsCount() int {
  354. return this.TotalCount
  355. }
  356. func (this *session) GetAll(p *SBParam) *utils.MySql_basket {
  357. products := []utils.MySql_basket_product{}
  358. for _, product := range this.Products {
  359. products = append(products, utils.MySql_basket_product{
  360. A_product_id: product.Id,
  361. A_price: this.makePrice(product.price, product.currency.Id),
  362. A_quantity: product.Quantity,
  363. RenderName: product.Name,
  364. RenderLink: product.Link,
  365. RenderPrice: product.Price,
  366. RenderQuantity: product.Quantity,
  367. RenderSum: product.Sum,
  368. })
  369. }
  370. currency := utils.MySql_basket_currency{
  371. Id: this.Currency.Id,
  372. Name: this.Currency.Name,
  373. Coefficient: this.Currency.Coefficient,
  374. Code: this.Currency.Code,
  375. Symbol: this.Currency.Symbol,
  376. }
  377. all := utils.MySql_basket{
  378. Products: &products,
  379. Currency: &currency,
  380. TotalSum: this.totalSum,
  381. TotalCount: this.TotalCount,
  382. RenderTotalSum: this.TotalSum,
  383. }
  384. return &all
  385. }