module_shop.go 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  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="/products/images/` + string(values[0]) + `/thumb-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" onchange="fave.ShopProductsAdd();">` +
  949. this.shop_GetAllAttributesSelectOptions(wrap) +
  950. `</select>` +
  951. `</div>` +
  952. `</div>` +
  953. `</div>` +
  954. `</div>` +
  955. `</div>`
  956. },
  957. },
  958. {
  959. Kind: builder.DFKTextArea,
  960. Caption: "Briefly",
  961. Name: "briefly",
  962. Value: data.A_briefly,
  963. Classes: "briefly wysiwyg",
  964. },
  965. {
  966. Kind: builder.DFKTextArea,
  967. Caption: "Product content",
  968. Name: "content",
  969. Value: data.A_content,
  970. Classes: "wysiwyg",
  971. },
  972. {
  973. Kind: builder.DFKText,
  974. Caption: "Product images",
  975. Name: "",
  976. Value: "",
  977. CallBack: func(field *builder.DataFormField) string {
  978. if data.A_id == 0 {
  979. return ``
  980. }
  981. return `<div class="form-group n6">` +
  982. `<div class="row">` +
  983. `<div class="col-md-3">` +
  984. `<label>Product images</label>` +
  985. `</div>` +
  986. `<div class="col-md-9">` +
  987. `<div class="list-wrapper">` +
  988. `<div id="list-images">` +
  989. this.shop_GetAllProductImages(wrap, data.A_id) +
  990. `</div>` +
  991. `<div class="list-button position-relative">` +
  992. `<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>` +
  993. `</div>` +
  994. `</div>` +
  995. `</div>` +
  996. `</div>` +
  997. `</div>`
  998. },
  999. },
  1000. {
  1001. Kind: builder.DFKCheckBox,
  1002. Caption: "Active",
  1003. Name: "active",
  1004. Value: utils.IntToStr(data.A_active),
  1005. },
  1006. {
  1007. Kind: builder.DFKSubmit,
  1008. Value: btn_caption,
  1009. Target: "add-edit-button",
  1010. },
  1011. })
  1012. if wrap.CurrSubModule == "add" {
  1013. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1014. } else {
  1015. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1016. }
  1017. } else if wrap.CurrSubModule == "categories-add" || wrap.CurrSubModule == "categories-modify" {
  1018. if wrap.CurrSubModule == "categories-add" {
  1019. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1020. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1021. {Name: "Add new category"},
  1022. })
  1023. } else {
  1024. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1025. {Name: "Categories", Link: "/cp/" + wrap.CurrModule + "/categories/"},
  1026. {Name: "Modify category"},
  1027. })
  1028. }
  1029. data := utils.MySql_shop_category{
  1030. A_id: 0,
  1031. A_user: 0,
  1032. A_name: "",
  1033. A_alias: "",
  1034. A_lft: 0,
  1035. A_rgt: 0,
  1036. }
  1037. if wrap.CurrSubModule == "categories-modify" {
  1038. if len(wrap.UrlArgs) != 3 {
  1039. return "", "", ""
  1040. }
  1041. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1042. return "", "", ""
  1043. }
  1044. err := wrap.DB.QueryRow(`
  1045. SELECT
  1046. id,
  1047. user,
  1048. name,
  1049. alias,
  1050. lft,
  1051. rgt
  1052. FROM
  1053. shop_cats
  1054. WHERE
  1055. id = ?
  1056. LIMIT 1;`,
  1057. utils.StrToInt(wrap.UrlArgs[2]),
  1058. ).Scan(
  1059. &data.A_id,
  1060. &data.A_user,
  1061. &data.A_name,
  1062. &data.A_alias,
  1063. &data.A_lft,
  1064. &data.A_rgt,
  1065. )
  1066. if err != nil {
  1067. return "", "", ""
  1068. }
  1069. }
  1070. btn_caption := "Add"
  1071. if wrap.CurrSubModule == "categories-modify" {
  1072. btn_caption = "Save"
  1073. }
  1074. parentId := 0
  1075. if wrap.CurrSubModule == "categories-modify" {
  1076. parentId = this.shop_GetCategoryParentId(wrap, data.A_id)
  1077. }
  1078. content += builder.DataForm(wrap, []builder.DataFormField{
  1079. {
  1080. Kind: builder.DFKHidden,
  1081. Name: "action",
  1082. Value: "shop-categories-modify",
  1083. },
  1084. {
  1085. Kind: builder.DFKHidden,
  1086. Name: "id",
  1087. Value: utils.IntToStr(data.A_id),
  1088. },
  1089. {
  1090. Kind: builder.DFKText,
  1091. Caption: "Parent",
  1092. Name: "parent",
  1093. Value: "0",
  1094. CallBack: func(field *builder.DataFormField) string {
  1095. return `<div class="form-group n2">` +
  1096. `<div class="row">` +
  1097. `<div class="col-md-3">` +
  1098. `<label for="lbl_parent">Parent</label>` +
  1099. `</div>` +
  1100. `<div class="col-md-9">` +
  1101. `<div>` +
  1102. `<select class="selectpicker form-control" id="lbl_parent" name="parent" data-live-search="true">` +
  1103. `<option title="Nothing selected" value="0">&mdash;</option>` +
  1104. this.shop_GetCategorySelectOptions(wrap, data.A_id, parentId, []int{}) +
  1105. `</select>` +
  1106. `</div>` +
  1107. `</div>` +
  1108. `</div>` +
  1109. `</div>`
  1110. },
  1111. },
  1112. {
  1113. Kind: builder.DFKText,
  1114. Caption: "Name",
  1115. Name: "name",
  1116. Value: data.A_name,
  1117. Required: true,
  1118. Min: "1",
  1119. Max: "255",
  1120. },
  1121. {
  1122. Kind: builder.DFKText,
  1123. Caption: "Alias",
  1124. Name: "alias",
  1125. Value: data.A_alias,
  1126. Hint: "Example: popular-products",
  1127. Max: "255",
  1128. },
  1129. {
  1130. Kind: builder.DFKSubmit,
  1131. Value: btn_caption,
  1132. Target: "add-edit-button",
  1133. },
  1134. })
  1135. if wrap.CurrSubModule == "categories-add" {
  1136. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1137. } else {
  1138. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1139. }
  1140. } else if wrap.CurrSubModule == "attributes-add" || wrap.CurrSubModule == "attributes-modify" {
  1141. if wrap.CurrSubModule == "attributes-add" {
  1142. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1143. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1144. {Name: "Add new attribute"},
  1145. })
  1146. } else {
  1147. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1148. {Name: "Attributes", Link: "/cp/" + wrap.CurrModule + "/attributes/"},
  1149. {Name: "Modify attribute"},
  1150. })
  1151. }
  1152. data := utils.MySql_shop_filter{
  1153. A_id: 0,
  1154. A_name: "",
  1155. A_filter: "",
  1156. }
  1157. if wrap.CurrSubModule == "attributes-modify" {
  1158. if len(wrap.UrlArgs) != 3 {
  1159. return "", "", ""
  1160. }
  1161. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1162. return "", "", ""
  1163. }
  1164. err := wrap.DB.QueryRow(`
  1165. SELECT
  1166. id,
  1167. name,
  1168. filter
  1169. FROM
  1170. shop_filters
  1171. WHERE
  1172. id = ?
  1173. LIMIT 1;`,
  1174. utils.StrToInt(wrap.UrlArgs[2]),
  1175. ).Scan(
  1176. &data.A_id,
  1177. &data.A_name,
  1178. &data.A_filter,
  1179. )
  1180. if err != nil {
  1181. return "", "", ""
  1182. }
  1183. }
  1184. btn_caption := "Add"
  1185. if wrap.CurrSubModule == "attributes-modify" {
  1186. btn_caption = "Save"
  1187. }
  1188. content += builder.DataForm(wrap, []builder.DataFormField{
  1189. {
  1190. Kind: builder.DFKHidden,
  1191. Name: "action",
  1192. Value: "shop-attributes-modify",
  1193. },
  1194. {
  1195. Kind: builder.DFKHidden,
  1196. Name: "id",
  1197. Value: utils.IntToStr(data.A_id),
  1198. },
  1199. {
  1200. Kind: builder.DFKText,
  1201. Caption: "Attribute name",
  1202. Name: "name",
  1203. Value: data.A_name,
  1204. Required: true,
  1205. Min: "1",
  1206. Max: "255",
  1207. },
  1208. {
  1209. Kind: builder.DFKText,
  1210. Caption: "Attribute in filter",
  1211. Name: "filter",
  1212. Value: data.A_filter,
  1213. Required: true,
  1214. Min: "1",
  1215. Max: "255",
  1216. },
  1217. {
  1218. Kind: builder.DFKText,
  1219. Caption: "Attribute values",
  1220. Name: "",
  1221. Value: "",
  1222. CallBack: func(field *builder.DataFormField) string {
  1223. return `<div class="form-group n4">` +
  1224. `<div class="row">` +
  1225. `<div class="col-md-3">` +
  1226. `<label>Attribute values</label>` +
  1227. `</div>` +
  1228. `<div class="col-md-9">` +
  1229. `<div class="list-wrapper">` +
  1230. `<div id="list">` +
  1231. this.shop_GetFilterValuesInputs(wrap, data.A_id) +
  1232. `</div>` +
  1233. `<div class="list-button"><button type="button" class="btn btn-success" onclick="fave.ShopAttributesAdd();">Add attribute value</button></div>` +
  1234. `</div>` +
  1235. `</div>` +
  1236. `</div>` +
  1237. `</div>`
  1238. },
  1239. },
  1240. {
  1241. Kind: builder.DFKSubmit,
  1242. Value: btn_caption,
  1243. Target: "add-edit-button",
  1244. },
  1245. })
  1246. if wrap.CurrSubModule == "attributes-add" {
  1247. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1248. } else {
  1249. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1250. }
  1251. } else if wrap.CurrSubModule == "currencies-add" || wrap.CurrSubModule == "currencies-modify" {
  1252. if wrap.CurrSubModule == "currencies-add" {
  1253. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1254. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1255. {Name: "Add new currency"},
  1256. })
  1257. } else {
  1258. content += this.getBreadCrumbs(wrap, &[]consts.BreadCrumb{
  1259. {Name: "Currencies", Link: "/cp/" + wrap.CurrModule + "/currencies/"},
  1260. {Name: "Modify currency"},
  1261. })
  1262. }
  1263. data := utils.MySql_shop_currency{
  1264. A_id: 0,
  1265. A_name: "",
  1266. A_coefficient: 0,
  1267. A_code: "",
  1268. A_symbol: "",
  1269. }
  1270. if wrap.CurrSubModule == "currencies-modify" {
  1271. if len(wrap.UrlArgs) != 3 {
  1272. return "", "", ""
  1273. }
  1274. if !utils.IsNumeric(wrap.UrlArgs[2]) {
  1275. return "", "", ""
  1276. }
  1277. err := wrap.DB.QueryRow(`
  1278. SELECT
  1279. id,
  1280. name,
  1281. coefficient,
  1282. code,
  1283. symbol
  1284. FROM
  1285. shop_currencies
  1286. WHERE
  1287. id = ?
  1288. LIMIT 1;`,
  1289. utils.StrToInt(wrap.UrlArgs[2]),
  1290. ).Scan(
  1291. &data.A_id,
  1292. &data.A_name,
  1293. &data.A_coefficient,
  1294. &data.A_code,
  1295. &data.A_symbol,
  1296. )
  1297. if err != nil {
  1298. return "", "", ""
  1299. }
  1300. }
  1301. btn_caption := "Add"
  1302. if wrap.CurrSubModule == "currencies-modify" {
  1303. btn_caption = "Save"
  1304. }
  1305. content += builder.DataForm(wrap, []builder.DataFormField{
  1306. {
  1307. Kind: builder.DFKHidden,
  1308. Name: "action",
  1309. Value: "shop-currencies-modify",
  1310. },
  1311. {
  1312. Kind: builder.DFKHidden,
  1313. Name: "id",
  1314. Value: utils.IntToStr(data.A_id),
  1315. },
  1316. {
  1317. Kind: builder.DFKText,
  1318. Caption: "Currency name",
  1319. Name: "name",
  1320. Value: data.A_name,
  1321. Required: true,
  1322. Min: "1",
  1323. Max: "255",
  1324. },
  1325. {
  1326. Kind: builder.DFKText,
  1327. Caption: "Currency coefficient",
  1328. Name: "coefficient",
  1329. Value: "0",
  1330. CallBack: func(field *builder.DataFormField) string {
  1331. return `<div class="form-group n3">` +
  1332. `<div class="row">` +
  1333. `<div class="col-md-3">` +
  1334. `<label for="lbl_coefficient">Currency coefficient</label>` +
  1335. `</div>` +
  1336. `<div class="col-md-9">` +
  1337. `<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>` +
  1338. `</div>` +
  1339. `</div>` +
  1340. `</div>`
  1341. },
  1342. },
  1343. {
  1344. Kind: builder.DFKText,
  1345. Caption: "Currency code",
  1346. Name: "code",
  1347. Value: data.A_code,
  1348. Required: true,
  1349. Min: "1",
  1350. Max: "10",
  1351. },
  1352. {
  1353. Kind: builder.DFKText,
  1354. Caption: "Currency symbol",
  1355. Name: "symbol",
  1356. Value: data.A_symbol,
  1357. Required: true,
  1358. Min: "1",
  1359. Max: "5",
  1360. },
  1361. {
  1362. Kind: builder.DFKSubmit,
  1363. Value: btn_caption,
  1364. Target: "add-edit-button",
  1365. },
  1366. })
  1367. if wrap.CurrSubModule == "currencies-add" {
  1368. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Add</button>`
  1369. } else {
  1370. sidebar += `<button class="btn btn-primary btn-sidebar" id="add-edit-button">Save</button>`
  1371. }
  1372. }
  1373. return this.getSidebarModules(wrap), content, sidebar
  1374. })
  1375. }