module_shop.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408
  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. depth.depth,
  278. MAX(main.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. parent.id AS parent_id
  289. FROM
  290. shop_cats AS node,
  291. shop_cats AS parent
  292. WHERE
  293. node.lft BETWEEN parent.lft AND parent.rgt AND
  294. node.id > 1
  295. ORDER BY
  296. node.lft ASC
  297. ) AS main
  298. LEFT JOIN (
  299. SELECT
  300. node.id,
  301. (COUNT(parent.id) - 1) AS depth
  302. FROM
  303. shop_cats AS node,
  304. shop_cats AS parent
  305. WHERE
  306. node.lft BETWEEN parent.lft AND parent.rgt
  307. GROUP BY
  308. node.id
  309. ORDER BY
  310. node.lft ASC
  311. ) AS depth ON depth.id = main.id
  312. WHERE
  313. main.id > 1 AND
  314. main.id <> main.parent_id AND
  315. main.alias = ?
  316. GROUP BY
  317. main.id
  318. ;`,
  319. wrap.UrlArgs[2],
  320. ).Scan(
  321. &row.A_id,
  322. &row.A_user,
  323. &row.A_name,
  324. &row.A_alias,
  325. &row.A_lft,
  326. &row.A_rgt,
  327. &row.A_depth,
  328. &row.A_parent,
  329. )
  330. if err != nil && err != wrapper.ErrNoRows {
  331. // System error 500
  332. utils.SystemErrorPageEngine(wrap.W, err)
  333. return
  334. } else if err == wrapper.ErrNoRows {
  335. // User error 404 page
  336. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  337. return
  338. }
  339. // Fix url
  340. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  341. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  342. return
  343. }
  344. // Render template
  345. wrap.RenderFrontEnd("shop-category", fetdata.New(wrap, row, false), http.StatusOK)
  346. return
  347. } else if len(wrap.UrlArgs) == 2 && wrap.UrlArgs[0] == "shop" && wrap.UrlArgs[1] != "" {
  348. // Shop product
  349. row := &utils.MySql_shop_product{}
  350. err := wrap.DB.QueryRow(`
  351. SELECT
  352. id,
  353. user,
  354. currency,
  355. price,
  356. name,
  357. alias,
  358. vendor,
  359. quantity,
  360. category,
  361. briefly,
  362. content,
  363. UNIX_TIMESTAMP(datetime) as datetime,
  364. active
  365. FROM
  366. shop_products
  367. WHERE
  368. active = 1 and
  369. alias = ?
  370. LIMIT 1;`,
  371. wrap.UrlArgs[1],
  372. ).Scan(
  373. &row.A_id,
  374. &row.A_user,
  375. &row.A_currency,
  376. &row.A_price,
  377. &row.A_name,
  378. &row.A_alias,
  379. &row.A_vendor,
  380. &row.A_quantity,
  381. &row.A_category,
  382. &row.A_briefly,
  383. &row.A_content,
  384. &row.A_datetime,
  385. &row.A_active,
  386. )
  387. if err != nil && err != wrapper.ErrNoRows {
  388. // System error 500
  389. utils.SystemErrorPageEngine(wrap.W, err)
  390. return
  391. } else if err == wrapper.ErrNoRows {
  392. // User error 404 page
  393. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  394. return
  395. }
  396. // Fix url
  397. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  398. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  399. return
  400. }
  401. // Render template
  402. wrap.RenderFrontEnd("shop-product", fetdata.New(wrap, row, false), http.StatusOK)
  403. return
  404. } else if len(wrap.UrlArgs) == 1 && wrap.UrlArgs[0] == "shop" {
  405. // Shop
  406. // Fix url
  407. if wrap.R.URL.Path[len(wrap.R.URL.Path)-1] != '/' {
  408. http.Redirect(wrap.W, wrap.R, wrap.R.URL.Path+"/"+utils.ExtractGetParams(wrap.R.RequestURI), 301)
  409. return
  410. }
  411. // Render template
  412. wrap.RenderFrontEnd("shop", fetdata.New(wrap, nil, false), http.StatusOK)
  413. return
  414. }
  415. // User error 404 page
  416. wrap.RenderFrontEnd("404", fetdata.New(wrap, nil, true), http.StatusNotFound)
  417. }, func(wrap *wrapper.Wrapper) (string, string, string) {
  418. content := ""
  419. sidebar := ""
  420. if wrap.CurrSubModule == "" || wrap.CurrSubModule == "default" {
  421. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  422. {Name: "List of products"},
  423. })
  424. // Load currencies
  425. currencies := this.shop_GetAllCurrencies(wrap)
  426. content += builder.DataTable(
  427. wrap,
  428. "shop_products",
  429. "id",
  430. "DESC",
  431. &[]builder.DataTableRow{
  432. {
  433. DBField: "id",
  434. },
  435. {
  436. DBField: "name",
  437. NameInTable: "Product / URL",
  438. CallBack: func(values *[]string) string {
  439. name := `<a href="/cp/` + wrap.CurrModule + `/modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + `</a>`
  440. alias := html.EscapeString((*values)[2])
  441. return `<div>` + name + `</div><div><small>/shop/` + alias + `/</small></div>`
  442. },
  443. },
  444. {
  445. DBField: "alias",
  446. },
  447. {
  448. DBField: "currency",
  449. },
  450. {
  451. DBField: "price",
  452. NameInTable: "Price",
  453. Classes: "d-none d-md-table-cell",
  454. CallBack: func(values *[]string) string {
  455. return `<div>` + utils.Float64ToStr(utils.StrToFloat64((*values)[4])) + `</div>` +
  456. `<div><small>` + currencies[utils.StrToInt((*values)[3])] + `</small></div>`
  457. },
  458. },
  459. {
  460. DBField: "datetime",
  461. DBExp: "UNIX_TIMESTAMP(`datetime`)",
  462. NameInTable: "Date / Time",
  463. Classes: "d-none d-lg-table-cell",
  464. CallBack: func(values *[]string) string {
  465. t := int64(utils.StrToInt((*values)[5]))
  466. return `<div>` + utils.UnixTimestampToFormat(t, "02.01.2006") + `</div>` +
  467. `<div><small>` + utils.UnixTimestampToFormat(t, "15:04:05") + `</small></div>`
  468. },
  469. },
  470. {
  471. DBField: "active",
  472. NameInTable: "Active",
  473. Classes: "d-none d-sm-table-cell",
  474. CallBack: func(values *[]string) string {
  475. return builder.CheckBox(utils.StrToInt((*values)[6]))
  476. },
  477. },
  478. },
  479. func(values *[]string) string {
  480. return builder.DataTableAction(&[]builder.DataTableActionRow{
  481. {
  482. Icon: assets.SysSvgIconView,
  483. Href: `/shop/` + (*values)[2] + `/`,
  484. Hint: "View",
  485. Target: "_blank",
  486. },
  487. {
  488. Icon: assets.SysSvgIconEdit,
  489. Href: "/cp/" + wrap.CurrModule + "/modify/" + (*values)[0] + "/",
  490. Hint: "Edit",
  491. },
  492. {
  493. Icon: assets.SysSvgIconRemove,
  494. Href: "javascript:fave.ActionDataTableDelete(this,'shop-delete','" +
  495. (*values)[0] + "','Are you sure want to delete product?');",
  496. Hint: "Delete",
  497. Classes: "delete",
  498. },
  499. })
  500. },
  501. "/cp/"+wrap.CurrModule+"/",
  502. nil,
  503. nil,
  504. true,
  505. )
  506. } else if wrap.CurrSubModule == "categories" {
  507. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  508. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  509. {Name: "List of categories"},
  510. })
  511. content += builder.DataTable(
  512. wrap,
  513. "shop_cats",
  514. "id",
  515. "ASC",
  516. &[]builder.DataTableRow{
  517. {
  518. DBField: "id",
  519. },
  520. {
  521. DBField: "user",
  522. },
  523. {
  524. DBField: "name",
  525. NameInTable: "Category",
  526. CallBack: func(values *[]string) string {
  527. depth := utils.StrToInt((*values)[4]) - 1
  528. if depth < 0 {
  529. depth = 0
  530. }
  531. sub := strings.Repeat("&mdash; ", depth)
  532. name := `<a href="/cp/` + wrap.CurrModule + `/categories-modify/` + (*values)[0] + `/">` + sub + html.EscapeString((*values)[2]) + `</a>`
  533. return `<div>` + name + `</div>`
  534. },
  535. },
  536. {
  537. DBField: "alias",
  538. },
  539. {
  540. DBField: "depth",
  541. },
  542. },
  543. func(values *[]string) string {
  544. return builder.DataTableAction(&[]builder.DataTableActionRow{
  545. {
  546. Icon: assets.SysSvgIconView,
  547. Href: `/shop/category/` + (*values)[3] + `/`,
  548. Hint: "View",
  549. Target: "_blank",
  550. },
  551. {
  552. Icon: assets.SysSvgIconEdit,
  553. Href: "/cp/" + wrap.CurrModule + "/categories-modify/" + (*values)[0] + "/",
  554. Hint: "Edit",
  555. },
  556. {
  557. Icon: assets.SysSvgIconRemove,
  558. Href: "javascript:fave.ActionDataTableDelete(this,'shop-categories-delete','" +
  559. (*values)[0] + "','Are you sure want to delete category?');",
  560. Hint: "Delete",
  561. Classes: "delete",
  562. },
  563. })
  564. },
  565. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  566. nil,
  567. func(limit_offset int, pear_page int) (*sqlw.Rows, error) {
  568. return wrap.DB.Query(
  569. `SELECT
  570. node.id,
  571. node.user,
  572. node.name,
  573. node.alias,
  574. (COUNT(parent.id) - 1) AS depth
  575. FROM
  576. shop_cats AS node,
  577. shop_cats AS parent
  578. WHERE
  579. node.lft BETWEEN parent.lft AND parent.rgt AND
  580. node.id > 1
  581. GROUP BY
  582. node.id
  583. ORDER BY
  584. node.lft ASC
  585. ;`,
  586. )
  587. },
  588. false,
  589. )
  590. } else if wrap.CurrSubModule == "attributes" {
  591. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  592. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  593. {Name: "List of attributes"},
  594. })
  595. content += builder.DataTable(
  596. wrap,
  597. "shop_filters",
  598. "id",
  599. "DESC",
  600. &[]builder.DataTableRow{
  601. {
  602. DBField: "id",
  603. },
  604. {
  605. DBField: "name",
  606. NameInTable: "Name",
  607. CallBack: func(values *[]string) string {
  608. name := `<a href="/cp/` + wrap.CurrModule + `/attributes-modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + `</a>`
  609. return `<div>` + name + `</div><div><small>` + html.EscapeString((*values)[2]) + `</small></div>`
  610. },
  611. },
  612. {
  613. DBField: "filter",
  614. },
  615. },
  616. func(values *[]string) string {
  617. return builder.DataTableAction(&[]builder.DataTableActionRow{
  618. {
  619. Icon: assets.SysSvgIconEdit,
  620. Href: "/cp/" + wrap.CurrModule + "/attributes-modify/" + (*values)[0] + "/",
  621. Hint: "Edit",
  622. },
  623. {
  624. Icon: assets.SysSvgIconRemove,
  625. Href: "javascript:fave.ActionDataTableDelete(this,'shop-attributes-delete','" +
  626. (*values)[0] + "','Are you sure want to delete attribute?');",
  627. Hint: "Delete",
  628. Classes: "delete",
  629. },
  630. })
  631. },
  632. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  633. nil,
  634. nil,
  635. true,
  636. )
  637. } else if wrap.CurrSubModule == "currencies" {
  638. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  639. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/" + wrap.CurrSubModule + "/"},
  640. {Name: "List of currencies"},
  641. })
  642. content += builder.DataTable(
  643. wrap,
  644. "shop_currencies",
  645. "id",
  646. "DESC",
  647. &[]builder.DataTableRow{
  648. {
  649. DBField: "id",
  650. },
  651. {
  652. DBField: "name",
  653. NameInTable: "Name",
  654. CallBack: func(values *[]string) string {
  655. name := `<a href="/cp/` + wrap.CurrModule + `/currencies-modify/` + (*values)[0] + `/">` + html.EscapeString((*values)[1]) + ` (` + (*values)[3] + `, ` + (*values)[4] + `)</a>`
  656. return `<div>` + name + `</div>`
  657. },
  658. },
  659. {
  660. DBField: "coefficient",
  661. NameInTable: "Coefficient",
  662. Classes: "d-none d-md-table-cell",
  663. CallBack: func(values *[]string) string {
  664. return utils.Float64ToStrF(utils.StrToFloat64((*values)[2]), "%.4f")
  665. },
  666. },
  667. {
  668. DBField: "code",
  669. },
  670. {
  671. DBField: "symbol",
  672. },
  673. },
  674. func(values *[]string) string {
  675. return builder.DataTableAction(&[]builder.DataTableActionRow{
  676. {
  677. Icon: assets.SysSvgIconEdit,
  678. Href: "/cp/" + wrap.CurrModule + "/currencies-modify/" + (*values)[0] + "/",
  679. Hint: "Edit",
  680. },
  681. {
  682. Icon: assets.SysSvgIconRemove,
  683. Href: "javascript:fave.ActionDataTableDelete(this,'shop-currencies-delete','" +
  684. (*values)[0] + "','Are you sure want to delete currency?');",
  685. Hint: "Delete",
  686. Classes: "delete",
  687. },
  688. })
  689. },
  690. "/cp/"+wrap.CurrModule+"/"+wrap.CurrSubModule+"/",
  691. nil,
  692. nil,
  693. true,
  694. )
  695. } else if wrap.CurrSubModule == "add" || wrap.CurrSubModule == "modify" {
  696. if wrap.CurrSubModule == "add" {
  697. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  698. {Name: "Add new product"},
  699. })
  700. } else {
  701. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  702. {Name: "Modify product"},
  703. })
  704. }
  705. data := utils.MySql_shop_product{
  706. A_id: 0,
  707. A_user: 0,
  708. A_currency: 0,
  709. A_price: 0,
  710. A_name: "",
  711. A_alias: "",
  712. A_vendor: "",
  713. A_quantity: 0,
  714. A_category: 0,
  715. A_briefly: "",
  716. A_content: "",
  717. A_datetime: 0,
  718. A_active: 0,
  719. }
  720. if wrap.CurrSubModule == "modify" {
  721. if len(wrap.UrlArgs) != 3 {
  722. return "", "", ""
  723. }
  724. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  725. return "", "", ""
  726. }
  727. err := wrap.DB.QueryRow(`
  728. SELECT
  729. id,
  730. user,
  731. currency,
  732. price,
  733. name,
  734. alias,
  735. vendor,
  736. quantity,
  737. category,
  738. briefly,
  739. content,
  740. active
  741. FROM
  742. shop_products
  743. WHERE
  744. id = ?
  745. LIMIT 1;`,
  746. utils.StrToInt(wrap.UrlArgs[2]),
  747. ).Scan(
  748. &data.A_id,
  749. &data.A_user,
  750. &data.A_currency,
  751. &data.A_price,
  752. &data.A_name,
  753. &data.A_alias,
  754. &data.A_vendor,
  755. &data.A_quantity,
  756. &data.A_category,
  757. &data.A_briefly,
  758. &data.A_content,
  759. &data.A_active,
  760. )
  761. if err != nil {
  762. return "", "", ""
  763. }
  764. }
  765. // All product current categories
  766. var selids []int
  767. if data.A_id > 0 {
  768. rows, err := wrap.DB.Query("SELECT category_id FROM shop_cat_product_rel WHERE product_id = ?;", data.A_id)
  769. if err == nil {
  770. defer rows.Close()
  771. values := make([]int, 1)
  772. scan := make([]interface{}, len(values))
  773. for i := range values {
  774. scan[i] = &values[i]
  775. }
  776. for rows.Next() {
  777. err = rows.Scan(scan...)
  778. if err == nil {
  779. selids = append(selids, int(values[0]))
  780. }
  781. }
  782. }
  783. }
  784. btn_caption := "Add"
  785. if wrap.CurrSubModule == "modify" {
  786. btn_caption = "Save"
  787. }
  788. content += builder.DataForm(wrap, []builder.DataFormField{
  789. {
  790. Kind: builder.DFKHidden,
  791. Name: "action",
  792. Value: "shop-modify",
  793. },
  794. {
  795. Kind: builder.DFKHidden,
  796. Name: "id",
  797. Value: utils.IntToStr(data.A_id),
  798. },
  799. {
  800. Kind: builder.DFKText,
  801. Caption: "Product name",
  802. Name: "name",
  803. Value: data.A_name,
  804. Required: true,
  805. Min: "1",
  806. Max: "255",
  807. },
  808. {
  809. Kind: builder.DFKText,
  810. Caption: "Product price",
  811. Name: "price",
  812. Value: "0",
  813. CallBack: func(field *builder.DataFormField) string {
  814. return `<div class="form-group n3">` +
  815. `<div class="row">` +
  816. `<div class="col-md-3">` +
  817. `<label for="lbl_price">Product price</label>` +
  818. `</div>` +
  819. `<div class="col-md-9">` +
  820. `<div>` +
  821. `<div class="row">` +
  822. `<div class="col-md-8">` +
  823. `<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>` +
  824. `<div class="d-md-none mb-3"></div>` +
  825. `</div>` +
  826. `<div class="col-md-4">` +
  827. `<select class="selectpicker form-control" id="lbl_currency" name="currency" data-live-search="true">` +
  828. this.shop_GetCurrencySelectOptions(wrap, data.A_currency) +
  829. `</select>` +
  830. `</div>` +
  831. `</div>` +
  832. `</div>` +
  833. `</div>` +
  834. `</div>` +
  835. `</div>`
  836. },
  837. },
  838. {
  839. Kind: builder.DFKText,
  840. Caption: "Product alias",
  841. Name: "alias",
  842. Value: data.A_alias,
  843. Hint: "Example: mobile-phone",
  844. Max: "255",
  845. },
  846. {
  847. Kind: builder.DFKText,
  848. Caption: "Vendor/Count",
  849. Name: "vendor",
  850. Value: "0",
  851. CallBack: func(field *builder.DataFormField) string {
  852. return `<div class="form-group n3">` +
  853. `<div class="row">` +
  854. `<div class="col-md-3">` +
  855. `<label for="lbl_vendor">Vendor/Count</label>` +
  856. `</div>` +
  857. `<div class="col-md-9">` +
  858. `<div>` +
  859. `<div class="row">` +
  860. `<div class="col-md-8">` +
  861. `<div><input class="form-control" type="text" id="lbl_vendor" name="vendor" value="` + html.EscapeString(data.A_vendor) + `" placeholder="" autocomplete="off"></div>` +
  862. `<div class="d-md-none mb-3"></div>` +
  863. `</div>` +
  864. `<div class="col-md-4">` +
  865. `<input class="form-control" type="number" step="1" id="lbl_quantity" name="quantity" value="` + utils.IntToStr(data.A_quantity) + `" placeholder="" autocomplete="off">` +
  866. `</div>` +
  867. `</div>` +
  868. `</div>` +
  869. `</div>` +
  870. `</div>` +
  871. `</div>`
  872. },
  873. },
  874. {
  875. Kind: builder.DFKText,
  876. Caption: "Category",
  877. Name: "category",
  878. Value: "0",
  879. CallBack: func(field *builder.DataFormField) string {
  880. return `<div class="form-group n2">` +
  881. `<div class="row">` +
  882. `<div class="col-md-3">` +
  883. `<label for="lbl_category">Category</label>` +
  884. `</div>` +
  885. `<div class="col-md-9">` +
  886. `<div>` +
  887. `<select class="selectpicker form-control" id="lbl_category" name="category" data-live-search="true">` +
  888. `<option title="Nothing selected" value="0">&mdash;</option>` +
  889. this.shop_GetCategorySelectOptions(wrap, 0, data.A_category, []int{}) +
  890. `</select>` +
  891. `</div>` +
  892. `</div>` +
  893. `</div>` +
  894. `</div>`
  895. },
  896. },
  897. {
  898. Kind: builder.DFKText,
  899. Caption: "Categories",
  900. Name: "cats",
  901. Value: "0",
  902. CallBack: func(field *builder.DataFormField) string {
  903. return `<div class="form-group n5">` +
  904. `<div class="row">` +
  905. `<div class="col-md-3">` +
  906. `<label for="lbl_cats">Categories</label>` +
  907. `</div>` +
  908. `<div class="col-md-9">` +
  909. `<div>` +
  910. `<select class="selectpicker form-control" id="lbl_cats" name="cats[]" data-live-search="true" multiple>` +
  911. this.shop_GetCategorySelectOptions(wrap, 0, 0, selids) +
  912. `</select>` +
  913. `</div>` +
  914. `</div>` +
  915. `</div>` +
  916. `</div>`
  917. },
  918. },
  919. {
  920. Kind: builder.DFKText,
  921. Caption: "Attributes",
  922. Name: "",
  923. Value: "",
  924. CallBack: func(field *builder.DataFormField) string {
  925. return `<div class="form-group n6">` +
  926. `<div class="row">` +
  927. `<div class="col-md-3">` +
  928. `<label>Attributes</label>` +
  929. `</div>` +
  930. `<div class="col-md-9">` +
  931. `<div class="list-wrapper">` +
  932. `<div id="list">` +
  933. this.shop_GetProductValuesInputs(wrap, data.A_id) +
  934. `</div>` +
  935. `<div class="list-button position-relative">` +
  936. `<select class="selectpicker form-control" id="lbl_attributes" data-live-search="true">` +
  937. this.shop_GetAllAttributesSelectOptions(wrap) +
  938. `</select>` +
  939. `<button type="button" class="btn btn-success btn-dynamic-remove" onclick="fave.ShopProductsAdd();">Add attribute</button>` +
  940. `</div>` +
  941. `</div>` +
  942. `</div>` +
  943. `</div>` +
  944. `</div>`
  945. },
  946. },
  947. {
  948. Kind: builder.DFKTextArea,
  949. Caption: "Briefly",
  950. Name: "briefly",
  951. Value: data.A_briefly,
  952. Classes: "briefly wysiwyg",
  953. },
  954. {
  955. Kind: builder.DFKTextArea,
  956. Caption: "Product content",
  957. Name: "content",
  958. Value: data.A_content,
  959. Classes: "wysiwyg",
  960. },
  961. {
  962. Kind: builder.DFKText,
  963. Caption: "Product images",
  964. Name: "",
  965. Value: "",
  966. CallBack: func(field *builder.DataFormField) string {
  967. if data.A_id == 0 {
  968. return ``
  969. }
  970. return `<div class="form-group n6">` +
  971. `<div class="row">` +
  972. `<div class="col-md-3">` +
  973. `<label>Product images</label>` +
  974. `</div>` +
  975. `<div class="col-md-9">` +
  976. `<div class="list-wrapper">` +
  977. `<div id="list-images">` +
  978. this.shop_GetAllProductImages(wrap, data.A_id) +
  979. `</div>` +
  980. `<div class="list-button position-relative">` +
  981. `<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>` +
  982. `</div>` +
  983. `</div>` +
  984. `</div>` +
  985. `</div>` +
  986. `</div>`
  987. },
  988. },
  989. {
  990. Kind: builder.DFKCheckBox,
  991. Caption: "Active",
  992. Name: "active",
  993. Value: utils.IntToStr(data.A_active),
  994. },
  995. {
  996. Kind: builder.DFKSubmit,
  997. Value: btn_caption,
  998. Target: "add-edit-button",
  999. },
  1000. })
  1001. if wrap.CurrSubModule == "add" {
  1002. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1003. } else {
  1004. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1005. }
  1006. } else if wrap.CurrSubModule == "categories-add" || wrap.CurrSubModule == "categories-modify" {
  1007. if wrap.CurrSubModule == "categories-add" {
  1008. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1009. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1010. {Name: "Add new category"},
  1011. })
  1012. } else {
  1013. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1014. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1015. {Name: "Modify category"},
  1016. })
  1017. }
  1018. data := utils.MySql_shop_category{
  1019. A_id: 0,
  1020. A_user: 0,
  1021. A_name: "",
  1022. A_alias: "",
  1023. A_lft: 0,
  1024. A_rgt: 0,
  1025. }
  1026. if wrap.CurrSubModule == "categories-modify" {
  1027. if len(wrap.UrlArgs) != 3 {
  1028. return "", "", ""
  1029. }
  1030. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1031. return "", "", ""
  1032. }
  1033. err := wrap.DB.QueryRow(`
  1034. SELECT
  1035. id,
  1036. user,
  1037. name,
  1038. alias,
  1039. lft,
  1040. rgt
  1041. FROM
  1042. shop_cats
  1043. WHERE
  1044. id = ?
  1045. LIMIT 1;`,
  1046. utils.StrToInt(wrap.UrlArgs[2]),
  1047. ).Scan(
  1048. &data.A_id,
  1049. &data.A_user,
  1050. &data.A_name,
  1051. &data.A_alias,
  1052. &data.A_lft,
  1053. &data.A_rgt,
  1054. )
  1055. if err != nil {
  1056. return "", "", ""
  1057. }
  1058. }
  1059. btn_caption := "Add"
  1060. if wrap.CurrSubModule == "categories-modify" {
  1061. btn_caption = "Save"
  1062. }
  1063. parentId := 0
  1064. if wrap.CurrSubModule == "categories-modify" {
  1065. parentId = this.shop_GetCategoryParentId(wrap, data.A_id)
  1066. }
  1067. content += builder.DataForm(wrap, []builder.DataFormField{
  1068. {
  1069. Kind: builder.DFKHidden,
  1070. Name: "action",
  1071. Value: "shop-categories-modify",
  1072. },
  1073. {
  1074. Kind: builder.DFKHidden,
  1075. Name: "id",
  1076. Value: utils.IntToStr(data.A_id),
  1077. },
  1078. {
  1079. Kind: builder.DFKText,
  1080. Caption: "Parent",
  1081. Name: "parent",
  1082. Value: "0",
  1083. CallBack: func(field *builder.DataFormField) string {
  1084. return `<div class="form-group n2">` +
  1085. `<div class="row">` +
  1086. `<div class="col-md-3">` +
  1087. `<label for="lbl_parent">Parent</label>` +
  1088. `</div>` +
  1089. `<div class="col-md-9">` +
  1090. `<div>` +
  1091. `<select class="selectpicker form-control" id="lbl_parent" name="parent" data-live-search="true">` +
  1092. `<option title="Nothing selected" value="0">&mdash;</option>` +
  1093. this.shop_GetCategorySelectOptions(wrap, data.A_id, parentId, []int{}) +
  1094. `</select>` +
  1095. `</div>` +
  1096. `</div>` +
  1097. `</div>` +
  1098. `</div>`
  1099. },
  1100. },
  1101. {
  1102. Kind: builder.DFKText,
  1103. Caption: "Name",
  1104. Name: "name",
  1105. Value: data.A_name,
  1106. Required: true,
  1107. Min: "1",
  1108. Max: "255",
  1109. },
  1110. {
  1111. Kind: builder.DFKText,
  1112. Caption: "Alias",
  1113. Name: "alias",
  1114. Value: data.A_alias,
  1115. Hint: "Example: popular-products",
  1116. Max: "255",
  1117. },
  1118. {
  1119. Kind: builder.DFKSubmit,
  1120. Value: btn_caption,
  1121. Target: "add-edit-button",
  1122. },
  1123. })
  1124. if wrap.CurrSubModule == "categories-add" {
  1125. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1126. } else {
  1127. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1128. }
  1129. } else if wrap.CurrSubModule == "attributes-add" || wrap.CurrSubModule == "attributes-modify" {
  1130. if wrap.CurrSubModule == "attributes-add" {
  1131. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1132. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1133. {Name: "Add new attribute"},
  1134. })
  1135. } else {
  1136. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1137. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1138. {Name: "Modify attribute"},
  1139. })
  1140. }
  1141. data := utils.MySql_shop_filter{
  1142. A_id: 0,
  1143. A_name: "",
  1144. A_filter: "",
  1145. }
  1146. if wrap.CurrSubModule == "attributes-modify" {
  1147. if len(wrap.UrlArgs) != 3 {
  1148. return "", "", ""
  1149. }
  1150. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1151. return "", "", ""
  1152. }
  1153. err := wrap.DB.QueryRow(`
  1154. SELECT
  1155. id,
  1156. name,
  1157. filter
  1158. FROM
  1159. shop_filters
  1160. WHERE
  1161. id = ?
  1162. LIMIT 1;`,
  1163. utils.StrToInt(wrap.UrlArgs[2]),
  1164. ).Scan(
  1165. &data.A_id,
  1166. &data.A_name,
  1167. &data.A_filter,
  1168. )
  1169. if err != nil {
  1170. return "", "", ""
  1171. }
  1172. }
  1173. btn_caption := "Add"
  1174. if wrap.CurrSubModule == "attributes-modify" {
  1175. btn_caption = "Save"
  1176. }
  1177. content += builder.DataForm(wrap, []builder.DataFormField{
  1178. {
  1179. Kind: builder.DFKHidden,
  1180. Name: "action",
  1181. Value: "shop-attributes-modify",
  1182. },
  1183. {
  1184. Kind: builder.DFKHidden,
  1185. Name: "id",
  1186. Value: utils.IntToStr(data.A_id),
  1187. },
  1188. {
  1189. Kind: builder.DFKText,
  1190. Caption: "Attribute name",
  1191. Name: "name",
  1192. Value: data.A_name,
  1193. Required: true,
  1194. Min: "1",
  1195. Max: "255",
  1196. },
  1197. {
  1198. Kind: builder.DFKText,
  1199. Caption: "Attribute in filter",
  1200. Name: "filter",
  1201. Value: data.A_filter,
  1202. Required: true,
  1203. Min: "1",
  1204. Max: "255",
  1205. },
  1206. {
  1207. Kind: builder.DFKText,
  1208. Caption: "Attribute values",
  1209. Name: "",
  1210. Value: "",
  1211. CallBack: func(field *builder.DataFormField) string {
  1212. return `<div class="form-group n4">` +
  1213. `<div class="row">` +
  1214. `<div class="col-md-3">` +
  1215. `<label>Attribute values</label>` +
  1216. `</div>` +
  1217. `<div class="col-md-9">` +
  1218. `<div class="list-wrapper">` +
  1219. `<div id="list">` +
  1220. this.shop_GetFilterValuesInputs(wrap, data.A_id) +
  1221. `</div>` +
  1222. `<div class="list-button"><button type="button" class="btn btn-success" onclick="fave.ShopAttributesAdd();">Add attribute value</button></div>` +
  1223. `</div>` +
  1224. `</div>` +
  1225. `</div>` +
  1226. `</div>`
  1227. },
  1228. },
  1229. {
  1230. Kind: builder.DFKSubmit,
  1231. Value: btn_caption,
  1232. Target: "add-edit-button",
  1233. },
  1234. })
  1235. if wrap.CurrSubModule == "attributes-add" {
  1236. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1237. } else {
  1238. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1239. }
  1240. } else if wrap.CurrSubModule == "currencies-add" || wrap.CurrSubModule == "currencies-modify" {
  1241. if wrap.CurrSubModule == "currencies-add" {
  1242. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1243. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1244. {Name: "Add new currency"},
  1245. })
  1246. } else {
  1247. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1248. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1249. {Name: "Modify currency"},
  1250. })
  1251. }
  1252. data := utils.MySql_shop_currency{
  1253. A_id: 0,
  1254. A_name: "",
  1255. A_coefficient: 0,
  1256. A_code: "",
  1257. A_symbol: "",
  1258. }
  1259. if wrap.CurrSubModule == "currencies-modify" {
  1260. if len(wrap.UrlArgs) != 3 {
  1261. return "", "", ""
  1262. }
  1263. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1264. return "", "", ""
  1265. }
  1266. err := wrap.DB.QueryRow(`
  1267. SELECT
  1268. id,
  1269. name,
  1270. coefficient,
  1271. code,
  1272. symbol
  1273. FROM
  1274. shop_currencies
  1275. WHERE
  1276. id = ?
  1277. LIMIT 1;`,
  1278. utils.StrToInt(wrap.UrlArgs[2]),
  1279. ).Scan(
  1280. &data.A_id,
  1281. &data.A_name,
  1282. &data.A_coefficient,
  1283. &data.A_code,
  1284. &data.A_symbol,
  1285. )
  1286. if err != nil {
  1287. return "", "", ""
  1288. }
  1289. }
  1290. btn_caption := "Add"
  1291. if wrap.CurrSubModule == "currencies-modify" {
  1292. btn_caption = "Save"
  1293. }
  1294. content += builder.DataForm(wrap, []builder.DataFormField{
  1295. {
  1296. Kind: builder.DFKHidden,
  1297. Name: "action",
  1298. Value: "shop-currencies-modify",
  1299. },
  1300. {
  1301. Kind: builder.DFKHidden,
  1302. Name: "id",
  1303. Value: utils.IntToStr(data.A_id),
  1304. },
  1305. {
  1306. Kind: builder.DFKText,
  1307. Caption: "Currency name",
  1308. Name: "name",
  1309. Value: data.A_name,
  1310. Required: true,
  1311. Min: "1",
  1312. Max: "255",
  1313. },
  1314. {
  1315. Kind: builder.DFKText,
  1316. Caption: "Currency coefficient",
  1317. Name: "coefficient",
  1318. Value: "0",
  1319. CallBack: func(field *builder.DataFormField) string {
  1320. return `<div class="form-group n3">` +
  1321. `<div class="row">` +
  1322. `<div class="col-md-3">` +
  1323. `<label for="lbl_coefficient">Currency coefficient</label>` +
  1324. `</div>` +
  1325. `<div class="col-md-9">` +
  1326. `<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>` +
  1327. `</div>` +
  1328. `</div>` +
  1329. `</div>`
  1330. },
  1331. },
  1332. {
  1333. Kind: builder.DFKText,
  1334. Caption: "Currency code",
  1335. Name: "code",
  1336. Value: data.A_code,
  1337. Required: true,
  1338. Min: "1",
  1339. Max: "10",
  1340. },
  1341. {
  1342. Kind: builder.DFKText,
  1343. Caption: "Currency symbol",
  1344. Name: "symbol",
  1345. Value: data.A_symbol,
  1346. Required: true,
  1347. Min: "1",
  1348. Max: "5",
  1349. },
  1350. {
  1351. Kind: builder.DFKSubmit,
  1352. Value: btn_caption,
  1353. Target: "add-edit-button",
  1354. },
  1355. })
  1356. if wrap.CurrSubModule == "currencies-add" {
  1357. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1358. } else {
  1359. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1360. }
  1361. }
  1362. return this.getSidebarModules(wrap), content, sidebar
  1363. })
  1364. }