module_shop.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. package modules
  2. import (
  3. "html"
  4. "net/http"
  5. "strings"
  6. "golang-fave/assets"
  7. "golang-fave/consts"
  8. "golang-fave/engine/builder"
  9. "golang-fave/engine/fetdata"
  10. "golang-fave/engine/sqlw"
  11. "golang-fave/engine/wrapper"
  12. "golang-fave/utils"
  13. )
  14. func (this *Modules) shop_GetCurrencySelectOptions(wrap *wrapper.Wrapper, id int) string {
  15. result := ``
  16. rows, err := wrap.DB.Query(
  17. `SELECT
  18. id,
  19. code
  20. FROM
  21. shop_currencies
  22. ORDER BY
  23. id ASC
  24. ;`,
  25. )
  26. if err == nil {
  27. defer rows.Close()
  28. values := make([]string, 2)
  29. scan := make([]interface{}, len(values))
  30. for i := range values {
  31. scan[i] = &values[i]
  32. }
  33. idStr := utils.IntToStr(id)
  34. for rows.Next() {
  35. err = rows.Scan(scan...)
  36. if err == nil {
  37. selected := ""
  38. if string(values[0]) == idStr {
  39. selected = " selected"
  40. }
  41. result += `<option title="` + html.EscapeString(string(values[1])) + `" value="` + html.EscapeString(string(values[0])) + `"` + selected + `>` + html.EscapeString(string(values[1])) + `</option>`
  42. }
  43. }
  44. }
  45. return result
  46. }
  47. func (this *Modules) shop_GetProductValuesInputs(wrap *wrapper.Wrapper, product_id int) string {
  48. result := ``
  49. rows, err := wrap.DB.Query(
  50. `SELECT
  51. shop_filters.id,
  52. shop_filters.name,
  53. shop_filters_values.id,
  54. shop_filters_values.name,
  55. IF(shop_filter_product_values.filter_value_id > 0, 1, 0) as selected
  56. FROM
  57. shop_filters
  58. LEFT JOIN shop_filters_values ON shop_filters_values.filter_id = shop_filters.id
  59. LEFT JOIN shop_filter_product_values ON shop_filter_product_values.filter_value_id = shop_filters_values.id
  60. LEFT JOIN (
  61. SELECT
  62. shop_filters_values.filter_id,
  63. shop_filter_product_values.product_id
  64. FROM
  65. shop_filter_product_values
  66. LEFT JOIN shop_filters_values ON shop_filters_values.id = shop_filter_product_values.filter_value_id
  67. WHERE
  68. shop_filter_product_values.product_id = ` + utils.IntToStr(product_id) + `
  69. GROUP BY
  70. shop_filters_values.filter_id
  71. ) as filter_used ON filter_used.filter_id = shop_filters.id
  72. WHERE
  73. (
  74. shop_filter_product_values.product_id = ` + utils.IntToStr(product_id) + ` OR
  75. shop_filter_product_values.product_id IS NULL
  76. ) AND
  77. filter_used.filter_id IS NOT NULL
  78. ORDER BY
  79. shop_filters.name ASC,
  80. shop_filters_values.name ASC
  81. ;`,
  82. )
  83. filter_ids := []int{}
  84. filter_names := map[int]string{}
  85. filter_values := map[int][]string{}
  86. if err == nil {
  87. defer rows.Close()
  88. values := make([]string, 5)
  89. scan := make([]interface{}, len(values))
  90. for i := range values {
  91. scan[i] = &values[i]
  92. }
  93. for rows.Next() {
  94. err = rows.Scan(scan...)
  95. if err == nil {
  96. filter_id := utils.StrToInt(string(values[0]))
  97. if !utils.InArrayInt(filter_ids, filter_id) {
  98. filter_ids = append(filter_ids, filter_id)
  99. }
  100. filter_names[filter_id] = html.EscapeString(string(values[1]))
  101. selected := ``
  102. if utils.StrToInt(string(values[4])) == 1 {
  103. selected = ` selected`
  104. }
  105. filter_values[filter_id] = append(filter_values[filter_id], `<option value="`+html.EscapeString(string(values[2]))+`"`+selected+`>`+html.EscapeString(string(values[3]))+`</option>`)
  106. }
  107. }
  108. }
  109. for _, filter_id := range filter_ids {
  110. result += `<div class="form-group" id="prod_attr_` + utils.IntToStr(filter_id) + `">` +
  111. `<div><b>` + filter_names[filter_id] + `</b></div>` +
  112. `<div class="position-relative">` +
  113. `<select class="selectpicker form-control" name="value.` + utils.IntToStr(filter_id) + `" autocomplete="off" required multiple>` +
  114. strings.Join(filter_values[filter_id], "") +
  115. `</select>` +
  116. `<button type="button" class="btn btn-danger btn-dynamic-remove" onclick="fave.ShopProductsRemove(this);">&times;</button>` +
  117. `</div>` +
  118. `</div>`
  119. }
  120. return result
  121. }
  122. func (this *Modules) shop_GetFilterValuesInputs(wrap *wrapper.Wrapper, filter_id int) string {
  123. result := ``
  124. rows, err := wrap.DB.Query(
  125. `SELECT
  126. id,
  127. name
  128. FROM
  129. shop_filters_values
  130. WHERE
  131. filter_id = ?
  132. ORDER BY
  133. name ASC
  134. ;`,
  135. filter_id,
  136. )
  137. if err == nil {
  138. defer rows.Close()
  139. values := make([]string, 2)
  140. scan := make([]interface{}, len(values))
  141. for i := range values {
  142. scan[i] = &values[i]
  143. }
  144. for rows.Next() {
  145. err = rows.Scan(scan...)
  146. if err == nil {
  147. result += `<div class="form-group position-relative"><input class="form-control" type="text" name="value.` + html.EscapeString(string(values[0])) + `" value="` + html.EscapeString(string(values[1])) + `" placeholder="" autocomplete="off" required><button type="button" class="btn btn-danger btn-dynamic-remove" onclick="fave.ShopAttributesRemove(this);">&times;</button></div>`
  148. }
  149. }
  150. }
  151. return result
  152. }
  153. func (this *Modules) shop_GetAllAttributesSelectOptions(wrap *wrapper.Wrapper) string {
  154. result := ``
  155. rows, err := wrap.DB.Query(
  156. `SELECT
  157. id,
  158. name,
  159. filter
  160. FROM
  161. shop_filters
  162. ORDER BY
  163. name ASC
  164. ;`,
  165. )
  166. result += `<option title="&mdash;" value="0">&mdash;</option>`
  167. if err == nil {
  168. defer rows.Close()
  169. values := make([]string, 3)
  170. scan := make([]interface{}, len(values))
  171. for i := range values {
  172. scan[i] = &values[i]
  173. }
  174. for rows.Next() {
  175. err = rows.Scan(scan...)
  176. if err == nil {
  177. result += `<option title="` + html.EscapeString(string(values[1])) + `" value="` + html.EscapeString(string(values[0])) + `">` + html.EscapeString(string(values[1])) + `</option>`
  178. }
  179. }
  180. }
  181. return result
  182. }
  183. func (this *Modules) shop_GetAllCurrencies(wrap *wrapper.Wrapper) map[int]string {
  184. result := map[int]string{}
  185. rows, err := wrap.DB.Query(
  186. `SELECT
  187. id,
  188. code
  189. FROM
  190. shop_currencies
  191. ORDER BY
  192. id ASC
  193. ;`,
  194. )
  195. if err == nil {
  196. defer rows.Close()
  197. values := make([]string, 2)
  198. scan := make([]interface{}, len(values))
  199. for i := range values {
  200. scan[i] = &values[i]
  201. }
  202. for rows.Next() {
  203. err = rows.Scan(scan...)
  204. if err == nil {
  205. result[utils.StrToInt(string(values[0]))] = html.EscapeString(string(values[1]))
  206. }
  207. }
  208. }
  209. return result
  210. }
  211. func (this *Modules) shop_GetAllProductImages(wrap *wrapper.Wrapper, product_id int) string {
  212. result := ``
  213. rows, err := wrap.DB.Query(
  214. `SELECT
  215. product_id,
  216. filename
  217. FROM
  218. shop_product_images
  219. WHERE
  220. product_id = ?
  221. ;`,
  222. product_id,
  223. )
  224. if err == nil {
  225. defer rows.Close()
  226. values := make([]string, 2)
  227. scan := make([]interface{}, len(values))
  228. for i := range values {
  229. scan[i] = &values[i]
  230. }
  231. for rows.Next() {
  232. err = rows.Scan(scan...)
  233. if err == nil {
  234. result += `<div class="attached-img"><a href="/products/images/` + html.EscapeString(string(values[0])) + `/` + html.EscapeString(string(values[1])) + `" title="` + html.EscapeString(string(values[1])) + `" target="_blank"><img src="/api/product-image/thumb-0/` + string(values[0]) + `/` + string(values[1]) + `" /></a>, <a href="javascript:fave.ShopProductsDeleteImage(this, ` + html.EscapeString(string(values[0])) + `, '` + html.EscapeString(string(values[1])) + `');">Delete</a></div>`
  235. }
  236. }
  237. }
  238. return result
  239. }
  240. func (this *Modules) RegisterModule_Shop() *Module {
  241. return this.newModule(MInfo{
  242. WantDB: true,
  243. Mount: "shop",
  244. Name: "Shop",
  245. Order: 2,
  246. System: false,
  247. Icon: assets.SysSvgIconList,
  248. Sub: &[]MISub{
  249. {Mount: "default", Name: "List of products", Show: true, Icon: assets.SysSvgIconList},
  250. {Mount: "add", Name: "Add new product", Show: true, Icon: assets.SysSvgIconPlus},
  251. {Mount: "modify", Name: "Modify product", Show: false},
  252. {Sep: true, Show: true},
  253. {Mount: "categories", Name: "List of categories", Show: true, Icon: assets.SysSvgIconList},
  254. {Mount: "categories-add", Name: "Add new category", Show: true, Icon: assets.SysSvgIconPlus},
  255. {Mount: "categories-modify", Name: "Modify category", Show: false},
  256. {Sep: true, Show: true},
  257. {Mount: "attributes", Name: "List of attributes", Show: true, Icon: assets.SysSvgIconList},
  258. {Mount: "attributes-add", Name: "Add new attribute", Show: true, Icon: assets.SysSvgIconPlus},
  259. {Mount: "attributes-modify", Name: "Modify attribute", Show: false},
  260. {Sep: true, Show: true},
  261. {Mount: "currencies", Name: "List of currencies", Show: true, Icon: assets.SysSvgIconList},
  262. {Mount: "currencies-add", Name: "Add new currency", Show: true, Icon: assets.SysSvgIconPlus},
  263. {Mount: "currencies-modify", Name: "Modify currency", Show: false},
  264. },
  265. }, func(wrap *wrapper.Wrapper) {
  266. if len(wrap.UrlArgs) == 3 && wrap.UrlArgs[0] == "shop" && wrap.UrlArgs[1] == "category" && wrap.UrlArgs[2] != "" {
  267. // Shop category
  268. row := &utils.MySql_shop_category{}
  269. err := wrap.DB.QueryRow(`
  270. SELECT
  271. main.id,
  272. main.user,
  273. main.name,
  274. main.alias,
  275. main.lft,
  276. main.rgt,
  277. main.depth,
  278. parent.id AS parent_id
  279. FROM
  280. (
  281. SELECT
  282. node.id,
  283. node.user,
  284. node.name,
  285. node.alias,
  286. node.lft,
  287. node.rgt,
  288. (COUNT(parent.id) - 1) AS depth
  289. FROM
  290. shop_cats AS node,
  291. shop_cats AS parent
  292. WHERE
  293. node.lft BETWEEN parent.lft AND parent.rgt
  294. GROUP BY
  295. node.id
  296. ORDER BY
  297. node.lft ASC
  298. ) AS main
  299. LEFT JOIN (
  300. SELECT
  301. node.id,
  302. node.user,
  303. node.name,
  304. node.alias,
  305. node.lft,
  306. node.rgt,
  307. (COUNT(parent.id) - 0) AS depth
  308. FROM
  309. shop_cats AS node,
  310. shop_cats AS parent
  311. WHERE
  312. node.lft BETWEEN parent.lft AND parent.rgt
  313. GROUP BY
  314. node.id
  315. ORDER BY
  316. node.lft ASC
  317. ) AS parent ON
  318. parent.depth = main.depth AND
  319. main.lft > parent.lft AND
  320. main.rgt < parent.rgt
  321. WHERE
  322. main.id > 1 AND
  323. main.alias = ?
  324. ORDER BY
  325. main.lft ASC
  326. ;`,
  327. wrap.UrlArgs[2],
  328. ).Scan(
  329. &row.A_id,
  330. &row.A_user,
  331. &row.A_name,
  332. &row.A_alias,
  333. &row.A_lft,
  334. &row.A_rgt,
  335. &row.A_depth,
  336. &row.A_parent,
  337. )
  338. if err != nil && err != wrapper.ErrNoRows {
  339. // System error 500
  340. utils.SystemErrorPageEngine(wrap.W, err)
  341. return
  342. } else if err == wrapper.ErrNoRows {
  343. // User error 404 page
  344. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  345. return
  346. }
  347. // Fix url
  348. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  349. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  350. return
  351. }
  352. // Render template
  353. wrap.RenderFrontEnd("shop-category", fetdata.New(wrap, row, false), http.StatusOK)
  354. return
  355. } else if len(wrap.UrlArgs) == 2 && wrap.UrlArgs[0] == "shop" && wrap.UrlArgs[1] != "" {
  356. // Shop product
  357. row := &utils.MySql_shop_product{}
  358. err := wrap.DB.QueryRow(`
  359. SELECT
  360. id,
  361. user,
  362. currency,
  363. price,
  364. name,
  365. alias,
  366. vendor,
  367. quantity,
  368. category,
  369. briefly,
  370. content,
  371. UNIX_TIMESTAMP(datetime) as datetime,
  372. active
  373. FROM
  374. shop_products
  375. WHERE
  376. active = 1 and
  377. alias = ?
  378. LIMIT 1;`,
  379. wrap.UrlArgs[1],
  380. ).Scan(
  381. &row.A_id,
  382. &row.A_user,
  383. &row.A_currency,
  384. &row.A_price,
  385. &row.A_name,
  386. &row.A_alias,
  387. &row.A_vendor,
  388. &row.A_quantity,
  389. &row.A_category,
  390. &row.A_briefly,
  391. &row.A_content,
  392. &row.A_datetime,
  393. &row.A_active,
  394. )
  395. if err != nil && err != wrapper.ErrNoRows {
  396. // System error 500
  397. utils.SystemErrorPageEngine(wrap.W, err)
  398. return
  399. } else if err == wrapper.ErrNoRows {
  400. // User error 404 page
  401. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  402. return
  403. }
  404. // Fix url
  405. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  406. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  407. return
  408. }
  409. // Render template
  410. wrap.RenderFrontEnd("shop-product", fetdata.New(wrap, row, false), http.StatusOK)
  411. return
  412. } else if len(wrap.UrlArgs) == 1 && wrap.UrlArgs[0] == "shop" {
  413. // Shop
  414. // Fix url
  415. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  416. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  417. return
  418. }
  419. // Render template
  420. wrap.RenderFrontEnd("shop", fetdata.New(wrap, nil, false), http.StatusOK)
  421. return
  422. } else if (*wrap.Config).Engine.MainModule == 2 {
  423. // Render template
  424. wrap.RenderFrontEnd("shop", fetdata.New(wrap, nil, false), http.StatusOK)
  425. return
  426. }
  427. // User error 404 page
  428. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  429. }, func(wrap *wrapper.Wrapper) (string, string, string) {
  430. content := ""
  431. sidebar := ""
  432. if wrap.CurrSubModule == "" || wrap.CurrSubModule == "default" {
  433. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  434. {Name: "List of products"},
  435. })
  436. // Load currencies
  437. currencies := this.shop_GetAllCurrencies(wrap)
  438. content += builder.DataTable(
  439. wrap,
  440. "shop_products",
  441. "id",
  442. "DESC",
  443. &[]builder.DataTableRow{
  444. {
  445. DBField: "id",
  446. },
  447. {
  448. DBField: "name",
  449. NameInTable: "Product / URL",
  450. CallBack: func(values *[]string) string {
  451. name := `<a href="/cp/` + wrap.CurrModule + `/modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + `</a>`
  452. alias := html.EscapeString((*values)[2])
  453. return `<div>` + name + `</div><div><small>/shop/` + alias + `/</small></div>`
  454. },
  455. },
  456. {
  457. DBField: "alias",
  458. },
  459. {
  460. DBField: "currency",
  461. },
  462. {
  463. DBField: "price",
  464. NameInTable: "Price",
  465. Classes: "d-none d-md-table-cell",
  466. CallBack: func(values *[]string) string {
  467. return `<div>` + utils.Float64ToStr(utils.StrToFloat64((*values)[4])) + `</div>` +
  468. `<div><small>` + currencies[utils.StrToInt((*values)[3])] + `</small></div>`
  469. },
  470. },
  471. {
  472. DBField: "datetime",
  473. DBExp: "UNIX_TIMESTAMP(`datetime`)",
  474. NameInTable: "Date / Time",
  475. Classes: "d-none d-lg-table-cell",
  476. CallBack: func(values *[]string) string {
  477. t := int64(utils.StrToInt((*values)[5]))
  478. return `<div>` + utils.UnixTimestampToFormat(t, "02.01.2006") + `</div>` +
  479. `<div><small>` + utils.UnixTimestampToFormat(t, "15:04:05") + `</small></div>`
  480. },
  481. },
  482. {
  483. DBField: "active",
  484. NameInTable: "Active",
  485. Classes: "d-none d-sm-table-cell",
  486. CallBack: func(values *[]string) string {
  487. return builder.CheckBox(utils.StrToInt((*values)[6]))
  488. },
  489. },
  490. },
  491. func(values *[]string) string {
  492. return builder.DataTableAction(&[]builder.DataTableActionRow{
  493. {
  494. Icon: assets.SysSvgIconView,
  495. Href: `/shop/` + (*values)[2] + `/`,
  496. Hint: "View",
  497. Target: "_blank",
  498. },
  499. {
  500. Icon: assets.SysSvgIconEdit,
  501. Href: "/cp/" + wrap.CurrModule + "/modify/" + (*values)[0] + "/",
  502. Hint: "Edit",
  503. },
  504. {
  505. Icon: assets.SysSvgIconRemove,
  506. Href: "javascript:fave.ActionDataTableDelete(this,'shop-delete','" +
  507. (*values)[0] + "','Are you sure want to delete product?');",
  508. Hint: "Delete",
  509. Classes: "delete",
  510. },
  511. })
  512. },
  513. "/cp/"+wrap.CurrModule+"/",
  514. nil,
  515. nil,
  516. true,
  517. )
  518. } else if wrap.CurrSubModule == "categories" {
  519. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  520. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  521. {Name: "List of categories"},
  522. })
  523. content += builder.DataTable(
  524. wrap,
  525. "shop_cats",
  526. "id",
  527. "ASC",
  528. &[]builder.DataTableRow{
  529. {
  530. DBField: "id",
  531. },
  532. {
  533. DBField: "user",
  534. },
  535. {
  536. DBField: "name",
  537. NameInTable: "Category",
  538. CallBack: func(values *[]string) string {
  539. depth := utils.StrToInt((*values)[4]) - 1
  540. if depth < 0 {
  541. depth = 0
  542. }
  543. sub := strings.Repeat("&mdash; ", depth)
  544. name := `<a href="/cp/` + wrap.CurrModule + `/categories-modify/` + (*values)[0] + `/">` + sub + html.EscapeString((*values)[2]) + `</a>`
  545. return `<div>` + name + `</div>`
  546. },
  547. },
  548. {
  549. DBField: "alias",
  550. },
  551. {
  552. DBField: "depth",
  553. },
  554. },
  555. func(values *[]string) string {
  556. return builder.DataTableAction(&[]builder.DataTableActionRow{
  557. {
  558. Icon: assets.SysSvgIconView,
  559. Href: `/shop/category/` + (*values)[3] + `/`,
  560. Hint: "View",
  561. Target: "_blank",
  562. },
  563. {
  564. Icon: assets.SysSvgIconEdit,
  565. Href: "/cp/" + wrap.CurrModule + "/categories-modify/" + (*values)[0] + "/",
  566. Hint: "Edit",
  567. },
  568. {
  569. Icon: assets.SysSvgIconRemove,
  570. Href: "javascript:fave.ActionDataTableDelete(this,'shop-categories-delete','" +
  571. (*values)[0] + "','Are you sure want to delete category?');",
  572. Hint: "Delete",
  573. Classes: "delete",
  574. },
  575. })
  576. },
  577. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  578. nil,
  579. func(limit_offset int, pear_page int) (*sqlw.Rows, error) {
  580. return wrap.DB.Query(
  581. `SELECT
  582. node.id,
  583. node.user,
  584. node.name,
  585. node.alias,
  586. (COUNT(parent.id) - 1) AS depth
  587. FROM
  588. shop_cats AS node,
  589. shop_cats AS parent
  590. WHERE
  591. node.lft BETWEEN parent.lft AND parent.rgt AND
  592. node.id > 1
  593. GROUP BY
  594. node.id
  595. ORDER BY
  596. node.lft ASC
  597. ;`,
  598. )
  599. },
  600. false,
  601. )
  602. } else if wrap.CurrSubModule == "attributes" {
  603. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  604. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  605. {Name: "List of attributes"},
  606. })
  607. content += builder.DataTable(
  608. wrap,
  609. "shop_filters",
  610. "id",
  611. "DESC",
  612. &[]builder.DataTableRow{
  613. {
  614. DBField: "id",
  615. },
  616. {
  617. DBField: "name",
  618. NameInTable: "Name",
  619. CallBack: func(values *[]string) string {
  620. name := `<a href="/cp/` + wrap.CurrModule + `/attributes-modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + `</a>`
  621. return `<div>` + name + `</div><div><small>` + html.EscapeString((*values)[2]) + `</small></div>`
  622. },
  623. },
  624. {
  625. DBField: "filter",
  626. },
  627. },
  628. func(values *[]string) string {
  629. return builder.DataTableAction(&[]builder.DataTableActionRow{
  630. {
  631. Icon: assets.SysSvgIconEdit,
  632. Href: "/cp/" + wrap.CurrModule + "/attributes-modify/" + (*values)[0] + "/",
  633. Hint: "Edit",
  634. },
  635. {
  636. Icon: assets.SysSvgIconRemove,
  637. Href: "javascript:fave.ActionDataTableDelete(this,'shop-attributes-delete','" +
  638. (*values)[0] + "','Are you sure want to delete attribute?');",
  639. Hint: "Delete",
  640. Classes: "delete",
  641. },
  642. })
  643. },
  644. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  645. nil,
  646. nil,
  647. true,
  648. )
  649. } else if wrap.CurrSubModule == "currencies" {
  650. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  651. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  652. {Name: "List of currencies"},
  653. })
  654. content += builder.DataTable(
  655. wrap,
  656. "shop_currencies",
  657. "id",
  658. "DESC",
  659. &[]builder.DataTableRow{
  660. {
  661. DBField: "id",
  662. },
  663. {
  664. DBField: "name",
  665. NameInTable: "Name",
  666. CallBack: func(values *[]string) string {
  667. name := `<a href="/cp/` + wrap.CurrModule + `/currencies-modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + ` (` + (*values)[3] + `, ` + (*values)[4] + `)</a>`
  668. return `<div>` + name + `</div>`
  669. },
  670. },
  671. {
  672. DBField: "coefficient",
  673. NameInTable: "Coefficient",
  674. Classes: "d-none d-md-table-cell",
  675. CallBack: func(values *[]string) string {
  676. return utils.Float64ToStrF(utils.StrToFloat64((*values)[2]), "%.4f")
  677. },
  678. },
  679. {
  680. DBField: "code",
  681. },
  682. {
  683. DBField: "symbol",
  684. },
  685. },
  686. func(values *[]string) string {
  687. return builder.DataTableAction(&[]builder.DataTableActionRow{
  688. {
  689. Icon: assets.SysSvgIconEdit,
  690. Href: "/cp/" + wrap.CurrModule + "/currencies-modify/" + (*values)[0] + "/",
  691. Hint: "Edit",
  692. },
  693. {
  694. Icon: assets.SysSvgIconRemove,
  695. Href: "javascript:fave.ActionDataTableDelete(this,'shop-currencies-delete','" +
  696. (*values)[0] + "','Are you sure want to delete currency?');",
  697. Hint: "Delete",
  698. Classes: "delete",
  699. },
  700. })
  701. },
  702. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  703. nil,
  704. nil,
  705. true,
  706. )
  707. } else if wrap.CurrSubModule == "add" || wrap.CurrSubModule == "modify" {
  708. if wrap.CurrSubModule == "add" {
  709. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  710. {Name: "Add new product"},
  711. })
  712. } else {
  713. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  714. {Name: "Modify product"},
  715. })
  716. }
  717. data := utils.MySql_shop_product{
  718. A_id: 0,
  719. A_user: 0,
  720. A_currency: 0,
  721. A_price: 0,
  722. A_name: "",
  723. A_alias: "",
  724. A_vendor: "",
  725. A_quantity: 0,
  726. A_category: 0,
  727. A_briefly: "",
  728. A_content: "",
  729. A_datetime: 0,
  730. A_active: 0,
  731. }
  732. if wrap.CurrSubModule == "modify" {
  733. if len(wrap.UrlArgs) != 3 {
  734. return "", "", ""
  735. }
  736. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  737. return "", "", ""
  738. }
  739. err := wrap.DB.QueryRow(`
  740. SELECT
  741. id,
  742. user,
  743. currency,
  744. price,
  745. name,
  746. alias,
  747. vendor,
  748. quantity,
  749. category,
  750. briefly,
  751. content,
  752. active
  753. FROM
  754. shop_products
  755. WHERE
  756. id = ?
  757. LIMIT 1;`,
  758. utils.StrToInt(wrap.UrlArgs[2]),
  759. ).Scan(
  760. &data.A_id,
  761. &data.A_user,
  762. &data.A_currency,
  763. &data.A_price,
  764. &data.A_name,
  765. &data.A_alias,
  766. &data.A_vendor,
  767. &data.A_quantity,
  768. &data.A_category,
  769. &data.A_briefly,
  770. &data.A_content,
  771. &data.A_active,
  772. )
  773. if err != nil {
  774. return "", "", ""
  775. }
  776. }
  777. // All product current categories
  778. var selids []int
  779. if data.A_id > 0 {
  780. rows, err := wrap.DB.Query("SELECT category_id FROM shop_cat_product_rel WHERE product_id = ?;", data.A_id)
  781. if err == nil {
  782. defer rows.Close()
  783. values := make([]int, 1)
  784. scan := make([]interface{}, len(values))
  785. for i := range values {
  786. scan[i] = &values[i]
  787. }
  788. for rows.Next() {
  789. err = rows.Scan(scan...)
  790. if err == nil {
  791. selids = append(selids, int(values[0]))
  792. }
  793. }
  794. }
  795. }
  796. btn_caption := "Add"
  797. if wrap.CurrSubModule == "modify" {
  798. btn_caption = "Save"
  799. }
  800. content += builder.DataForm(wrap, []builder.DataFormField{
  801. {
  802. Kind: builder.DFKHidden,
  803. Name: "action",
  804. Value: "shop-modify",
  805. },
  806. {
  807. Kind: builder.DFKHidden,
  808. Name: "id",
  809. Value: utils.IntToStr(data.A_id),
  810. },
  811. {
  812. Kind: builder.DFKText,
  813. Caption: "Product name",
  814. Name: "name",
  815. Value: data.A_name,
  816. Required: true,
  817. Min: "1",
  818. Max: "255",
  819. },
  820. {
  821. Kind: builder.DFKText,
  822. Caption: "Product price",
  823. Name: "price",
  824. Value: "0",
  825. CallBack: func(field *builder.DataFormField) string {
  826. return `<div class="form-group n3">` +
  827. `<div class="row">` +
  828. `<div class="col-md-3">` +
  829. `<label for="lbl_price">Product price</label>` +
  830. `</div>` +
  831. `<div class="col-md-9">` +
  832. `<div>` +
  833. `<div class="row">` +
  834. `<div class="col-md-8">` +
  835. `<div><input class="form-control" type="number" step="0.01" id="lbl_price" name="price" value="` + utils.Float64ToStr(data.A_price) + `" placeholder="" autocomplete="off" required></div>` +
  836. `<div class="d-md-none mb-3"></div>` +
  837. `</div>` +
  838. `<div class="col-md-4">` +
  839. `<select class="selectpicker form-control" id="lbl_currency" name="currency" data-live-search="true">` +
  840. this.shop_GetCurrencySelectOptions(wrap, data.A_currency) +
  841. `</select>` +
  842. `</div>` +
  843. `</div>` +
  844. `</div>` +
  845. `</div>` +
  846. `</div>` +
  847. `</div>`
  848. },
  849. },
  850. {
  851. Kind: builder.DFKText,
  852. Caption: "Product alias",
  853. Name: "alias",
  854. Value: data.A_alias,
  855. Hint: "Example: mobile-phone",
  856. Max: "255",
  857. },
  858. {
  859. Kind: builder.DFKText,
  860. Caption: "Vendor/Count",
  861. Name: "vendor",
  862. Value: "0",
  863. CallBack: func(field *builder.DataFormField) string {
  864. return `<div class="form-group n3">` +
  865. `<div class="row">` +
  866. `<div class="col-md-3">` +
  867. `<label for="lbl_vendor">Vendor/Count</label>` +
  868. `</div>` +
  869. `<div class="col-md-9">` +
  870. `<div>` +
  871. `<div class="row">` +
  872. `<div class="col-md-8">` +
  873. `<div><input class="form-control" type="text" id="lbl_vendor" name="vendor" value="` + html.EscapeString(data.A_vendor) + `" placeholder="" autocomplete="off"></div>` +
  874. `<div class="d-md-none mb-3"></div>` +
  875. `</div>` +
  876. `<div class="col-md-4">` +
  877. `<input class="form-control" type="number" step="1" id="lbl_quantity" name="quantity" value="` + utils.IntToStr(data.A_quantity) + `" placeholder="" autocomplete="off">` +
  878. `</div>` +
  879. `</div>` +
  880. `</div>` +
  881. `</div>` +
  882. `</div>` +
  883. `</div>`
  884. },
  885. },
  886. {
  887. Kind: builder.DFKText,
  888. Caption: "Category",
  889. Name: "category",
  890. Value: "0",
  891. CallBack: func(field *builder.DataFormField) string {
  892. return `<div class="form-group n2">` +
  893. `<div class="row">` +
  894. `<div class="col-md-3">` +
  895. `<label for="lbl_category">Category</label>` +
  896. `</div>` +
  897. `<div class="col-md-9">` +
  898. `<div>` +
  899. `<select class="selectpicker form-control" id="lbl_category" name="category" data-live-search="true">` +
  900. `<option title="Nothing selected" value="0">&mdash;</option>` +
  901. this.shop_GetCategorySelectOptions(wrap, 0, data.A_category, []int{}) +
  902. `</select>` +
  903. `</div>` +
  904. `</div>` +
  905. `</div>` +
  906. `</div>`
  907. },
  908. },
  909. {
  910. Kind: builder.DFKText,
  911. Caption: "Categories",
  912. Name: "cats",
  913. Value: "0",
  914. CallBack: func(field *builder.DataFormField) string {
  915. return `<div class="form-group n5">` +
  916. `<div class="row">` +
  917. `<div class="col-md-3">` +
  918. `<label for="lbl_cats">Categories</label>` +
  919. `</div>` +
  920. `<div class="col-md-9">` +
  921. `<div>` +
  922. `<select class="selectpicker form-control" id="lbl_cats" name="cats[]" data-live-search="true" multiple>` +
  923. this.shop_GetCategorySelectOptions(wrap, 0, 0, selids) +
  924. `</select>` +
  925. `</div>` +
  926. `</div>` +
  927. `</div>` +
  928. `</div>`
  929. },
  930. },
  931. {
  932. Kind: builder.DFKText,
  933. Caption: "Attributes",
  934. Name: "",
  935. Value: "",
  936. CallBack: func(field *builder.DataFormField) string {
  937. return `<div class="form-group n6">` +
  938. `<div class="row">` +
  939. `<div class="col-md-3">` +
  940. `<label>Attributes</label>` +
  941. `</div>` +
  942. `<div class="col-md-9">` +
  943. `<div class="list-wrapper">` +
  944. `<div id="list">` +
  945. this.shop_GetProductValuesInputs(wrap, data.A_id) +
  946. `</div>` +
  947. `<div class="list-button position-relative">` +
  948. `<select class="selectpicker form-control" id="lbl_attributes" data-live-search="true">` +
  949. this.shop_GetAllAttributesSelectOptions(wrap) +
  950. `</select>` +
  951. `<button type="button" class="btn btn-success btn-dynamic-remove" onclick="fave.ShopProductsAdd();">Add attribute</button>` +
  952. `</div>` +
  953. `</div>` +
  954. `</div>` +
  955. `</div>` +
  956. `</div>`
  957. },
  958. },
  959. {
  960. Kind: builder.DFKTextArea,
  961. Caption: "Briefly",
  962. Name: "briefly",
  963. Value: data.A_briefly,
  964. Classes: "briefly wysiwyg",
  965. },
  966. {
  967. Kind: builder.DFKTextArea,
  968. Caption: "Product content",
  969. Name: "content",
  970. Value: data.A_content,
  971. Classes: "wysiwyg",
  972. },
  973. {
  974. Kind: builder.DFKText,
  975. Caption: "Product images",
  976. Name: "",
  977. Value: "",
  978. CallBack: func(field *builder.DataFormField) string {
  979. if data.A_id == 0 {
  980. return ``
  981. }
  982. return `<div class="form-group n6">` +
  983. `<div class="row">` +
  984. `<div class="col-md-3">` +
  985. `<label>Product images</label>` +
  986. `</div>` +
  987. `<div class="col-md-9">` +
  988. `<div class="list-wrapper">` +
  989. `<div id="list-images">` +
  990. this.shop_GetAllProductImages(wrap, data.A_id) +
  991. `</div>` +
  992. `<div class="list-button position-relative">` +
  993. `<input class="form-control ignore-lost-data" type="file" id="file" name="file" style="font-size:13px;" /><button type="button" class="btn btn-success btn-dynamic-remove" onclick="fave.ShopProductsUploadImage('shop-upload-image', ` + utils.IntToStr(data.A_id) + `, 'file');">Upload</button>` +
  994. `</div>` +
  995. `</div>` +
  996. `</div>` +
  997. `</div>` +
  998. `</div>`
  999. },
  1000. },
  1001. {
  1002. Kind: builder.DFKCheckBox,
  1003. Caption: "Active",
  1004. Name: "active",
  1005. Value: utils.IntToStr(data.A_active),
  1006. },
  1007. {
  1008. Kind: builder.DFKSubmit,
  1009. Value: btn_caption,
  1010. Target: "add-edit-button",
  1011. },
  1012. })
  1013. if wrap.CurrSubModule == "add" {
  1014. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1015. } else {
  1016. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1017. }
  1018. } else if wrap.CurrSubModule == "categories-add" || wrap.CurrSubModule == "categories-modify" {
  1019. if wrap.CurrSubModule == "categories-add" {
  1020. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1021. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1022. {Name: "Add new category"},
  1023. })
  1024. } else {
  1025. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1026. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1027. {Name: "Modify category"},
  1028. })
  1029. }
  1030. data := utils.MySql_shop_category{
  1031. A_id: 0,
  1032. A_user: 0,
  1033. A_name: "",
  1034. A_alias: "",
  1035. A_lft: 0,
  1036. A_rgt: 0,
  1037. }
  1038. if wrap.CurrSubModule == "categories-modify" {
  1039. if len(wrap.UrlArgs) != 3 {
  1040. return "", "", ""
  1041. }
  1042. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1043. return "", "", ""
  1044. }
  1045. err := wrap.DB.QueryRow(`
  1046. SELECT
  1047. id,
  1048. user,
  1049. name,
  1050. alias,
  1051. lft,
  1052. rgt
  1053. FROM
  1054. shop_cats
  1055. WHERE
  1056. id = ?
  1057. LIMIT 1;`,
  1058. utils.StrToInt(wrap.UrlArgs[2]),
  1059. ).Scan(
  1060. &data.A_id,
  1061. &data.A_user,
  1062. &data.A_name,
  1063. &data.A_alias,
  1064. &data.A_lft,
  1065. &data.A_rgt,
  1066. )
  1067. if err != nil {
  1068. return "", "", ""
  1069. }
  1070. }
  1071. btn_caption := "Add"
  1072. if wrap.CurrSubModule == "categories-modify" {
  1073. btn_caption = "Save"
  1074. }
  1075. parentId := 0
  1076. if wrap.CurrSubModule == "categories-modify" {
  1077. parentId = this.shop_GetCategoryParentId(wrap, data.A_id)
  1078. }
  1079. content += builder.DataForm(wrap, []builder.DataFormField{
  1080. {
  1081. Kind: builder.DFKHidden,
  1082. Name: "action",
  1083. Value: "shop-categories-modify",
  1084. },
  1085. {
  1086. Kind: builder.DFKHidden,
  1087. Name: "id",
  1088. Value: utils.IntToStr(data.A_id),
  1089. },
  1090. {
  1091. Kind: builder.DFKText,
  1092. Caption: "Parent",
  1093. Name: "parent",
  1094. Value: "0",
  1095. CallBack: func(field *builder.DataFormField) string {
  1096. return `<div class="form-group n2">` +
  1097. `<div class="row">` +
  1098. `<div class="col-md-3">` +
  1099. `<label for="lbl_parent">Parent</label>` +
  1100. `</div>` +
  1101. `<div class="col-md-9">` +
  1102. `<div>` +
  1103. `<select class="selectpicker form-control" id="lbl_parent" name="parent" data-live-search="true">` +
  1104. `<option title="Nothing selected" value="0">&mdash;</option>` +
  1105. this.shop_GetCategorySelectOptions(wrap, data.A_id, parentId, []int{}) +
  1106. `</select>` +
  1107. `</div>` +
  1108. `</div>` +
  1109. `</div>` +
  1110. `</div>`
  1111. },
  1112. },
  1113. {
  1114. Kind: builder.DFKText,
  1115. Caption: "Name",
  1116. Name: "name",
  1117. Value: data.A_name,
  1118. Required: true,
  1119. Min: "1",
  1120. Max: "255",
  1121. },
  1122. {
  1123. Kind: builder.DFKText,
  1124. Caption: "Alias",
  1125. Name: "alias",
  1126. Value: data.A_alias,
  1127. Hint: "Example: popular-products",
  1128. Max: "255",
  1129. },
  1130. {
  1131. Kind: builder.DFKSubmit,
  1132. Value: btn_caption,
  1133. Target: "add-edit-button",
  1134. },
  1135. })
  1136. if wrap.CurrSubModule == "categories-add" {
  1137. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1138. } else {
  1139. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1140. }
  1141. } else if wrap.CurrSubModule == "attributes-add" || wrap.CurrSubModule == "attributes-modify" {
  1142. if wrap.CurrSubModule == "attributes-add" {
  1143. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1144. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1145. {Name: "Add new attribute"},
  1146. })
  1147. } else {
  1148. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1149. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1150. {Name: "Modify attribute"},
  1151. })
  1152. }
  1153. data := utils.MySql_shop_filter{
  1154. A_id: 0,
  1155. A_name: "",
  1156. A_filter: "",
  1157. }
  1158. if wrap.CurrSubModule == "attributes-modify" {
  1159. if len(wrap.UrlArgs) != 3 {
  1160. return "", "", ""
  1161. }
  1162. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1163. return "", "", ""
  1164. }
  1165. err := wrap.DB.QueryRow(`
  1166. SELECT
  1167. id,
  1168. name,
  1169. filter
  1170. FROM
  1171. shop_filters
  1172. WHERE
  1173. id = ?
  1174. LIMIT 1;`,
  1175. utils.StrToInt(wrap.UrlArgs[2]),
  1176. ).Scan(
  1177. &data.A_id,
  1178. &data.A_name,
  1179. &data.A_filter,
  1180. )
  1181. if err != nil {
  1182. return "", "", ""
  1183. }
  1184. }
  1185. btn_caption := "Add"
  1186. if wrap.CurrSubModule == "attributes-modify" {
  1187. btn_caption = "Save"
  1188. }
  1189. content += builder.DataForm(wrap, []builder.DataFormField{
  1190. {
  1191. Kind: builder.DFKHidden,
  1192. Name: "action",
  1193. Value: "shop-attributes-modify",
  1194. },
  1195. {
  1196. Kind: builder.DFKHidden,
  1197. Name: "id",
  1198. Value: utils.IntToStr(data.A_id),
  1199. },
  1200. {
  1201. Kind: builder.DFKText,
  1202. Caption: "Attribute name",
  1203. Name: "name",
  1204. Value: data.A_name,
  1205. Required: true,
  1206. Min: "1",
  1207. Max: "255",
  1208. },
  1209. {
  1210. Kind: builder.DFKText,
  1211. Caption: "Attribute in filter",
  1212. Name: "filter",
  1213. Value: data.A_filter,
  1214. Required: true,
  1215. Min: "1",
  1216. Max: "255",
  1217. },
  1218. {
  1219. Kind: builder.DFKText,
  1220. Caption: "Attribute values",
  1221. Name: "",
  1222. Value: "",
  1223. CallBack: func(field *builder.DataFormField) string {
  1224. return `<div class="form-group n4">` +
  1225. `<div class="row">` +
  1226. `<div class="col-md-3">` +
  1227. `<label>Attribute values</label>` +
  1228. `</div>` +
  1229. `<div class="col-md-9">` +
  1230. `<div class="list-wrapper">` +
  1231. `<div id="list">` +
  1232. this.shop_GetFilterValuesInputs(wrap, data.A_id) +
  1233. `</div>` +
  1234. `<div class="list-button"><button type="button" class="btn btn-success" onclick="fave.ShopAttributesAdd();">Add attribute value</button></div>` +
  1235. `</div>` +
  1236. `</div>` +
  1237. `</div>` +
  1238. `</div>`
  1239. },
  1240. },
  1241. {
  1242. Kind: builder.DFKSubmit,
  1243. Value: btn_caption,
  1244. Target: "add-edit-button",
  1245. },
  1246. })
  1247. if wrap.CurrSubModule == "attributes-add" {
  1248. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1249. } else {
  1250. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1251. }
  1252. } else if wrap.CurrSubModule == "currencies-add" || wrap.CurrSubModule == "currencies-modify" {
  1253. if wrap.CurrSubModule == "currencies-add" {
  1254. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1255. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1256. {Name: "Add new currency"},
  1257. })
  1258. } else {
  1259. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1260. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1261. {Name: "Modify currency"},
  1262. })
  1263. }
  1264. data := utils.MySql_shop_currency{
  1265. A_id: 0,
  1266. A_name: "",
  1267. A_coefficient: 0,
  1268. A_code: "",
  1269. A_symbol: "",
  1270. }
  1271. if wrap.CurrSubModule == "currencies-modify" {
  1272. if len(wrap.UrlArgs) != 3 {
  1273. return "", "", ""
  1274. }
  1275. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1276. return "", "", ""
  1277. }
  1278. err := wrap.DB.QueryRow(`
  1279. SELECT
  1280. id,
  1281. name,
  1282. coefficient,
  1283. code,
  1284. symbol
  1285. FROM
  1286. shop_currencies
  1287. WHERE
  1288. id = ?
  1289. LIMIT 1;`,
  1290. utils.StrToInt(wrap.UrlArgs[2]),
  1291. ).Scan(
  1292. &data.A_id,
  1293. &data.A_name,
  1294. &data.A_coefficient,
  1295. &data.A_code,
  1296. &data.A_symbol,
  1297. )
  1298. if err != nil {
  1299. return "", "", ""
  1300. }
  1301. }
  1302. btn_caption := "Add"
  1303. if wrap.CurrSubModule == "currencies-modify" {
  1304. btn_caption = "Save"
  1305. }
  1306. content += builder.DataForm(wrap, []builder.DataFormField{
  1307. {
  1308. Kind: builder.DFKHidden,
  1309. Name: "action",
  1310. Value: "shop-currencies-modify",
  1311. },
  1312. {
  1313. Kind: builder.DFKHidden,
  1314. Name: "id",
  1315. Value: utils.IntToStr(data.A_id),
  1316. },
  1317. {
  1318. Kind: builder.DFKText,
  1319. Caption: "Currency name",
  1320. Name: "name",
  1321. Value: data.A_name,
  1322. Required: true,
  1323. Min: "1",
  1324. Max: "255",
  1325. },
  1326. {
  1327. Kind: builder.DFKText,
  1328. Caption: "Currency coefficient",
  1329. Name: "coefficient",
  1330. Value: "0",
  1331. CallBack: func(field *builder.DataFormField) string {
  1332. return `<div class="form-group n3">` +
  1333. `<div class="row">` +
  1334. `<div class="col-md-3">` +
  1335. `<label for="lbl_coefficient">Currency coefficient</label>` +
  1336. `</div>` +
  1337. `<div class="col-md-9">` +
  1338. `<div><input class="form-control" type="number" step="0.0001" id="lbl_coefficient" name="coefficient" value="` + utils.Float64ToStrF(data.A_coefficient, "%.4f") + `" placeholder="" autocomplete="off" required></div>` +
  1339. `</div>` +
  1340. `</div>` +
  1341. `</div>`
  1342. },
  1343. },
  1344. {
  1345. Kind: builder.DFKText,
  1346. Caption: "Currency code",
  1347. Name: "code",
  1348. Value: data.A_code,
  1349. Required: true,
  1350. Min: "1",
  1351. Max: "10",
  1352. },
  1353. {
  1354. Kind: builder.DFKText,
  1355. Caption: "Currency symbol",
  1356. Name: "symbol",
  1357. Value: data.A_symbol,
  1358. Required: true,
  1359. Min: "1",
  1360. Max: "5",
  1361. },
  1362. {
  1363. Kind: builder.DFKSubmit,
  1364. Value: btn_caption,
  1365. Target: "add-edit-button",
  1366. },
  1367. })
  1368. if wrap.CurrSubModule == "currencies-add" {
  1369. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1370. } else {
  1371. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1372. }
  1373. }
  1374. return this.getSidebarModules(wrap), content, sidebar
  1375. })
  1376. }