uc_attribute.admin.inc 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. <?php
  2. /**
  3. * @file
  4. * Attribute administration menu items.
  5. */
  6. /**
  7. * Displays a paged list and overview of existing product attributes.
  8. */
  9. function uc_attribute_admin() {
  10. $header = array(
  11. array('data' => t('Name'), 'field' => 'a.name', 'sort' => 'asc'),
  12. array('data' => t('Label'), 'field' => 'a.label'),
  13. t('Required'),
  14. array('data' => t('List position'), 'field' => 'a.ordering'),
  15. t('Number of options'),
  16. t('Display type'),
  17. array('data' => t('Operations'), 'colspan' => 3),
  18. );
  19. $display_types = _uc_attribute_display_types();
  20. $query = db_select('uc_attributes', 'a')->extend('PagerDefault')->extend('TableSort')
  21. ->fields('a', array('aid', 'name', 'label', 'required', 'ordering', 'display'))
  22. ->orderByHeader($header)
  23. ->limit(30);
  24. $rows = array();
  25. $result = $query->execute();
  26. foreach ($result as $attr) {
  27. $attr->options = db_query('SELECT COUNT(*) FROM {uc_attribute_options} WHERE aid = :aid', array(':aid' => $attr->aid))->fetchField();
  28. if (empty($attr->label)) {
  29. $attr->label = $attr->name;
  30. }
  31. $rows[] = array(
  32. check_plain($attr->name),
  33. check_plain($attr->label),
  34. $attr->required == 1 ? t('Yes') : t('No'),
  35. $attr->ordering,
  36. $attr->options,
  37. $display_types[$attr->display],
  38. l(t('edit'), 'admin/store/products/attributes/' . $attr->aid . '/edit'),
  39. l(t('options'), 'admin/store/products/attributes/' . $attr->aid . '/options'),
  40. l(t('delete'), 'admin/store/products/attributes/' . $attr->aid . '/delete'),
  41. );
  42. }
  43. $build['attributes'] = array(
  44. '#theme' => 'table',
  45. '#header' => $header,
  46. '#rows' => $rows,
  47. '#empty' => t('No product attributes have been added yet.'),
  48. );
  49. $build['pager'] = array(
  50. '#theme' => 'pager',
  51. );
  52. return $build;
  53. }
  54. /**
  55. * Form builder for product attributes.
  56. *
  57. * @see uc_attribute_form_submit()
  58. *
  59. * @ingroup forms
  60. */
  61. function uc_attribute_form($form, &$form_state, $attribute = NULL) {
  62. // If an attribute specified, add its ID as a hidden value.
  63. if (!empty($attribute)) {
  64. $form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
  65. drupal_set_title(t('Edit attribute: %name', array('%name' => $attribute->name)), PASS_THROUGH);
  66. }
  67. if (isset($attribute->name)) {
  68. if (empty($attribute->label)) {
  69. $attribute->label = $attribute->name;
  70. }
  71. $name = $attribute->name;
  72. $label = $attribute->label;
  73. }
  74. else {
  75. $name = $label = '';
  76. }
  77. $form['name'] = array(
  78. '#type' => 'textfield',
  79. '#title' => t('Name'),
  80. '#description' => t('The name of the attribute used in administrative forms'),
  81. '#default_value' => $name,
  82. '#required' => TRUE,
  83. );
  84. $form['label'] = array(
  85. '#type' => 'textfield',
  86. '#title' => t('Label'),
  87. '#description' => t("Enter a label that customers will see instead of the attribute name. Use &lt;none&gt; if you don't want a title to appear at all."),
  88. '#default_value' => $label,
  89. '#maxlength' => 255,
  90. );
  91. $form['description'] = array(
  92. '#type' => 'textfield',
  93. '#title' => t('Help text'),
  94. '#description' => t('<b>Optional.</b> Enter the help text that will display beneath the attribute on product add to cart forms.'),
  95. '#default_value' => isset($attribute->description) ? $attribute->description : '',
  96. '#maxlength' => 255,
  97. );
  98. $form['required'] = array(
  99. '#type' => 'checkbox',
  100. '#title' => t('Make this attribute required, forcing the customer to choose an option.'),
  101. '#description' => t('Selecting this for an attribute will disregard any default option you specify.<br />May be overridden at the product level.'),
  102. '#default_value' => isset($attribute->required) ? $attribute->required : 0,
  103. );
  104. $form['display'] = array(
  105. '#type' => 'select',
  106. '#title' => t('Display type'),
  107. '#description' => t('This specifies how the options for this attribute will be presented.<br />May be overridden at the product level.'),
  108. '#options' => _uc_attribute_display_types(),
  109. '#default_value' => isset($attribute->display) ? $attribute->display : 1,
  110. );
  111. $form['ordering'] = array(
  112. '#type' => 'weight',
  113. '#delta' => 25,
  114. '#title' => t('List position'),
  115. '#description' => t('Multiple attributes on an add to cart form are sorted by this value and then by their name.<br />May be overridden at the product level.'),
  116. '#default_value' => isset($attribute->ordering) ? $attribute->ordering : 0,
  117. );
  118. $form['actions'] = array('#type' => 'actions');
  119. $form['actions']['submit'] = array(
  120. '#type' => 'submit',
  121. '#value' => t('Submit'),
  122. '#suffix' => l(t('Cancel'), 'admin/store/products/attributes'),
  123. );
  124. return $form;
  125. }
  126. /**
  127. * Form submission handler for uc_attribute_form().
  128. *
  129. * @see uc_attribute_form()
  130. */
  131. function uc_attribute_form_submit($form, &$form_state) {
  132. if (!empty($form_state['values']['aid'])) {
  133. drupal_write_record('uc_attributes', $form_state['values'], 'aid');
  134. $form_state['redirect'] = 'admin/store/products/attributes';
  135. }
  136. else {
  137. drupal_write_record('uc_attributes', $form_state['values']);
  138. if ($form_state['values']['display'] == 0) {
  139. // No options needed/allowed for Textfield display type.
  140. $form_state['redirect'] = 'admin/store/products/attributes';
  141. }
  142. else {
  143. // All other display types we redirect to add options.
  144. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  145. }
  146. }
  147. }
  148. /**
  149. * Confirms the deletion of the given attribute.
  150. *
  151. * @see uc_attribute_delete_confirm_submit()
  152. */
  153. function uc_attribute_delete_confirm($form, &$form_state, $attribute) {
  154. // If we got a bunk attribute, kick out an error message.
  155. if (empty($attribute)) {
  156. drupal_set_message(t('There is no attribute with that ID.'), 'error');
  157. drupal_goto('admin/store/products/attributes');
  158. }
  159. $form['aid'] = array('#type' => 'value', '#value' => $attribute->aid);
  160. $count = db_query("SELECT COUNT(*) FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchField();
  161. $output = confirm_form($form, t('Are you sure you want to delete the attribute %name?', array('%name' => $attribute->name)),
  162. 'admin/store/products/attributes', format_plural($count, 'There is 1 product with this attribute.', 'There are @count products with this attribute.'),
  163. t('Delete'), t('Cancel'));
  164. return $output;
  165. }
  166. /**
  167. * Form submission handler for uc_attribute_delete_confirm().
  168. *
  169. * @see uc_attribute_delete_confirm()
  170. */
  171. function uc_attribute_delete_confirm_submit($form, &$form_state) {
  172. if ($form_state['values']['confirm']) {
  173. $attribute = uc_attribute_load($form_state['values']['aid']);
  174. $options = array_keys($attribute->options);
  175. if ($options) {
  176. db_delete('uc_class_attribute_options')
  177. ->condition('oid', $options, 'IN')
  178. ->execute();
  179. db_delete('uc_product_options')
  180. ->condition('oid', $options, 'IN')
  181. ->execute();
  182. }
  183. if ($nodes = db_query("SELECT nid FROM {uc_product_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchCol()) {
  184. db_delete('uc_product_adjustments')
  185. ->condition('nid', $nodes, 'IN')
  186. ->execute();
  187. }
  188. db_delete('uc_class_attributes')
  189. ->condition('aid', $form_state['values']['aid'])
  190. ->execute();
  191. db_delete('uc_product_attributes')
  192. ->condition('aid', $form_state['values']['aid'])
  193. ->execute();
  194. db_delete('uc_attribute_options')
  195. ->condition('aid', $form_state['values']['aid'])
  196. ->execute();
  197. db_delete('uc_attributes')
  198. ->condition('aid', $form_state['values']['aid'])
  199. ->execute();
  200. drupal_set_message(t('Product attribute deleted.'));
  201. $form_state['redirect'] = 'admin/store/products/attributes';
  202. }
  203. }
  204. /**
  205. * Displays options and the modifications to products they represent.
  206. *
  207. * @see uc_attribute_options_form_validate()
  208. * @see uc_attribute_options_form_submit()
  209. *
  210. * @ingroup forms
  211. */
  212. function uc_attribute_options_form($form, &$form_state, $attribute) {
  213. // Set an appropriate title.
  214. drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
  215. // Store the attribute ID in the form array.
  216. $form['aid'] = array(
  217. '#type' => 'value',
  218. '#value' => $attribute->aid,
  219. );
  220. $form['options'] = array();
  221. // Loop through all the options on an attribute.
  222. foreach ($attribute->options as $key => $data) {
  223. $form['options'][$key] = array(
  224. 'name' => array(
  225. '#markup' => check_plain($data->name),
  226. ),
  227. 'cost' => array(
  228. '#theme' => 'uc_price',
  229. '#price' => $data->cost,
  230. ),
  231. 'price' => array(
  232. '#theme' => 'uc_price',
  233. '#price' => $data->price,
  234. ),
  235. 'weight' => array(
  236. '#markup' => (string) $data->weight,
  237. ),
  238. 'ordering' => array(
  239. '#type' => 'weight',
  240. '#delta' => 50,
  241. '#default_value' => $data->ordering,
  242. '#attributes' => array('class' => array('uc-attribute-option-table-ordering')),
  243. ),
  244. 'edit' => array('#markup' => l(t('edit'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/edit')),
  245. 'delete' => array('#markup' => l(t('delete'), 'admin/store/products/attributes/' . $attribute->aid . '/options/' . $key . '/delete')),
  246. );
  247. }
  248. if (count($form['options'])) {
  249. $form['options']['#tree'] = TRUE;
  250. $form['actions'] = array('#type' => 'actions');
  251. $form['actions']['submit'] = array(
  252. '#type' => 'submit',
  253. '#value' => t('Save changes'),
  254. '#weight' => 10,
  255. );
  256. }
  257. return $form;
  258. }
  259. /**
  260. * Form submission handler for uc_attribute_options_form().
  261. *
  262. * @see uc_attribute_options_form()
  263. * @see uc_object_options_form_submit()
  264. */
  265. function uc_attribute_options_form_submit($form, &$form_state) {
  266. foreach ($form_state['values']['options'] as $oid => $option) {
  267. db_update('uc_attribute_options')
  268. ->fields(array(
  269. 'ordering' => $option['ordering'],
  270. ))
  271. ->condition('oid', $oid)
  272. ->execute();
  273. }
  274. drupal_set_message(t('The changes have been saved.'));
  275. }
  276. /**
  277. * Formats an attribute and its options.
  278. *
  279. * @param $variables
  280. * An associative array containing:
  281. * - form: A render element representing the form.
  282. *
  283. * @ingroup themeable
  284. */
  285. function theme_uc_attribute_options_form($variables) {
  286. $form = $variables['form'];
  287. $header = array(t('Name'), t('Default cost'), t('Default price'), t('Default weight'), array('data' => t('List position'), 'sort' => 'asc'), array('data' => t('Operations'), 'colspan' => 2));
  288. $rows = array();
  289. foreach (element_children($form['options']) as $oid) {
  290. $rows[] = array(
  291. 'data' => array(
  292. drupal_render($form['options'][$oid]['name']),
  293. drupal_render($form['options'][$oid]['cost']),
  294. drupal_render($form['options'][$oid]['price']),
  295. drupal_render($form['options'][$oid]['weight']),
  296. drupal_render($form['options'][$oid]['ordering']),
  297. drupal_render($form['options'][$oid]['edit']),
  298. drupal_render($form['options'][$oid]['delete']),
  299. ),
  300. 'class' => array('draggable'),
  301. );
  302. }
  303. drupal_add_tabledrag('uc-attribute-option-table', 'order', 'sibling', 'uc-attribute-option-table-ordering');
  304. $output = theme('table', array(
  305. 'header' => $header,
  306. 'rows' => $rows,
  307. 'attributes' => array('id' => 'uc-attribute-option-table'),
  308. 'empty' => t('No options for this attribute have been added yet.'),
  309. ));
  310. $output .= drupal_render_children($form);
  311. return $output;
  312. }
  313. /**
  314. * Form builder for attribute options.
  315. *
  316. * @see uc_attribute_option_form_validate()
  317. * @see uc_attribute_option_form_submit()
  318. *
  319. * @ingroup forms
  320. */
  321. function uc_attribute_option_form($form, &$form_state, $attribute, $option = NULL) {
  322. // If we got a bunk attribute, kick out an error message.
  323. if (empty($attribute)) {
  324. drupal_set_message(t('There is no attribute with that ID.'), 'error');
  325. drupal_goto('admin/store/products/attributes');
  326. }
  327. $aid = $attribute->aid;
  328. $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
  329. if (!empty($option)) {
  330. $form['oid'] = array('#type' => 'hidden', '#value' => $option->oid);
  331. drupal_set_title(t('Edit option: %name', array('%name' => $option->name)), PASS_THROUGH);
  332. }
  333. else {
  334. $option = new stdClass();
  335. $option->name = '';
  336. $option->ordering = 0;
  337. $option->cost = 0;
  338. $option->price = 0;
  339. $option->weight = 0;
  340. drupal_set_title(t('Options for %name', array('%name' => $attribute->name)), PASS_THROUGH);
  341. }
  342. $form['name'] = array(
  343. '#type' => 'textfield',
  344. '#title' => t('Name'),
  345. '#description' => t('This name will appear to customers on product add to cart forms.'),
  346. '#default_value' => $option->name,
  347. '#required' => TRUE,
  348. '#weight' => 0,
  349. );
  350. $form['ordering'] = array(
  351. '#type' => 'weight',
  352. '#delta' => 50,
  353. '#title' => t('List position'),
  354. '#description' => t('Options will be listed sorted by this value and then by their name.<br />May be overridden at the product level.'),
  355. '#default_value' => $option->ordering,
  356. '#weight' => 4,
  357. );
  358. $form['adjustments'] = array(
  359. '#type' => 'fieldset',
  360. '#title' => t('Default adjustments'),
  361. '#description' => t('Enter a positive or negative value for each adjustment applied when this option is selected.<br />Any of these may be overriden at the product level.'),
  362. '#collapsible' => FALSE,
  363. '#weight' => 8,
  364. );
  365. $form['adjustments']['cost'] = array(
  366. '#type' => 'uc_price',
  367. '#title' => t('Cost'),
  368. '#default_value' => $option->cost,
  369. '#weight' => 1,
  370. '#allow_negative' => TRUE,
  371. );
  372. $form['adjustments']['price'] = array(
  373. '#type' => 'uc_price',
  374. '#title' => t('Price'),
  375. '#default_value' => $option->price,
  376. '#weight' => 2,
  377. '#allow_negative' => TRUE,
  378. );
  379. $form['adjustments']['weight'] = array(
  380. '#type' => 'textfield',
  381. '#title' => t('Weight'),
  382. '#default_value' => $option->weight,
  383. '#weight' => 3,
  384. );
  385. $form['actions'] = array('#type' => 'actions');
  386. $form['actions']['submit'] = array(
  387. '#type' => 'submit',
  388. '#value' => t('Submit'),
  389. '#suffix' => l(t('Cancel'), 'admin/store/products/attributes/' . $aid . '/options'),
  390. '#weight' => 10,
  391. );
  392. return $form;
  393. }
  394. /**
  395. * Validates number formats.
  396. *
  397. * @see uc_attribute_option_form()
  398. * @see uc_attribute_option_form_submit()
  399. */
  400. function uc_attribute_option_form_validate($form, &$form_state) {
  401. $pattern = '/^-?\d*(\.\d*)?$/';
  402. $price_error = t('This must be in a valid number format. No commas and only one decimal point.');
  403. if (!is_numeric($form_state['values']['weight']) && !preg_match($pattern, $form_state['values']['weight'])) {
  404. form_set_error('weight', $price_error);
  405. }
  406. }
  407. /**
  408. * Form submission handler for uc_attribute_option_form().
  409. *
  410. * @see uc_attribute_option_form()
  411. * @see uc_attribute_option_form_validate()
  412. */
  413. function uc_attribute_option_form_submit($form, &$form_state) {
  414. if (!isset($form_state['values']['oid'])) {
  415. drupal_write_record('uc_attribute_options', $form_state['values']);
  416. drupal_set_message(t('Created new option %option.', array('%option' => $form_state['values']['name'])));
  417. watchdog('uc_attribute', 'Created new option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/add');
  418. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/add';
  419. }
  420. else {
  421. drupal_write_record('uc_attribute_options', $form_state['values'], array('aid', 'oid'));
  422. drupal_set_message(t('Updated option %option.', array('%option' => $form_state['values']['name'])));
  423. watchdog('uc_attribute', 'Updated option %option.', array('%option' => $form_state['values']['name']), WATCHDOG_NOTICE, 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options/' . $form_state['values']['oid']);
  424. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  425. }
  426. }
  427. /**
  428. * Confirms deletion of the given attribute option.
  429. *
  430. * @see uc_attribute_option_delete_confirm_submit()
  431. */
  432. function uc_attribute_option_delete_confirm($form, &$form_state, $attribute, $option) {
  433. if (empty($option)) {
  434. drupal_set_message(t('There is no option with that ID.'), 'error');
  435. drupal_goto('admin/store/products/attributes/' . $attribute->aid . '/options');
  436. }
  437. $aid = $attribute->aid;
  438. $oid = $option->oid;
  439. $form['aid'] = array('#type' => 'value', '#value' => $aid);
  440. $form['oid'] = array('#type' => 'value', '#value' => $oid);
  441. $output = confirm_form($form, t('Are you sure you want to delete the option %name?', array('%name' => $option->name)), 'admin/store/products/attributes/' . $aid . '/options', '', t('Delete'), t('Cancel'));
  442. return $output;
  443. }
  444. /**
  445. * Form submission handler for uc_attribute_option_delete_confirm().
  446. *
  447. * @see uc_attribute_option_delete_confirm()
  448. */
  449. function uc_attribute_option_delete_confirm_submit($form, &$form_state) {
  450. if ($form_state['values']['confirm']) {
  451. $match = 'i:' . $form_state['values']['aid'] . ';s:' . strlen($form_state['values']['oid']) . ':"' . $form_state['values']['oid'] . '";';
  452. db_delete('uc_product_adjustments')
  453. ->condition('combination', '%' . db_like($match) . '%', 'LIKE')
  454. ->execute();
  455. $select = db_select('uc_attribute_options', 'ao')
  456. ->where('{uc_class_attribute_options}.oid = ao.oid')
  457. ->condition('ao.oid', $form_state['values']['oid']);
  458. $select->addExpression('1');
  459. db_delete('uc_class_attribute_options')
  460. ->condition('', $select, 'EXISTS')
  461. ->execute();
  462. $select = db_select('uc_attribute_options', 'ao')
  463. ->where('{uc_product_options}.oid = ao.oid')
  464. ->condition('ao.oid', $form_state['values']['oid']);
  465. $select->addExpression('1');
  466. db_delete('uc_product_options')
  467. ->condition('', $select, 'EXISTS')
  468. ->execute();
  469. db_delete('uc_attribute_options')
  470. ->condition('oid', $form_state['values']['oid'])
  471. ->execute();
  472. }
  473. $form_state['redirect'] = 'admin/store/products/attributes/' . $form_state['values']['aid'] . '/options';
  474. }
  475. /**
  476. * Form to associate attributes with products or classes.
  477. *
  478. * @see uc_object_attributes_form_submit()
  479. * @see theme_uc_object_attributes_form()
  480. *
  481. * @ingroup forms
  482. */
  483. function uc_object_attributes_form($form, &$form_state, $object, $type, $view = 'overview') {
  484. switch ($type) {
  485. case 'class':
  486. $class = $object;
  487. $id = $class->pcid;
  488. if (empty($class->name)) {
  489. drupal_goto('admin/store/products/classes/' . $id);
  490. }
  491. drupal_set_title($class->name);
  492. $attributes = uc_class_get_attributes($id);
  493. break;
  494. case 'product':
  495. default:
  496. $product = $object;
  497. $id = $product->nid;
  498. if (empty($product->title)) {
  499. drupal_goto('node/' . $id);
  500. }
  501. drupal_set_title($product->title);
  502. $attributes = uc_product_get_attributes($id);
  503. }
  504. $used_aids = array();
  505. foreach ($attributes as $attribute) {
  506. $used_aids[] = $attribute->aid;
  507. }
  508. if ($view == 'overview') {
  509. $form['#tree'] = TRUE;
  510. $form['attributes'] = array();
  511. if (count($attributes) > 0) {
  512. foreach ($attributes as $attribute) {
  513. $option = isset($attribute->options[$attribute->default_option]) ? $attribute->options[$attribute->default_option] : NULL;
  514. $form['attributes'][$attribute->aid] = array(
  515. 'remove' => array(
  516. '#type' => 'checkbox',
  517. '#title' => t('Remove'),
  518. '#title_display' => 'invisible',
  519. '#default_value' => 0,
  520. ),
  521. 'name' => array(
  522. '#markup' => check_plain($attribute->name),
  523. ),
  524. 'label' => array(
  525. '#type' => 'textfield',
  526. '#title' => t('Label'),
  527. '#title_display' => 'invisible',
  528. '#default_value' => empty($attribute->label) ? $attribute->name : $attribute->label,
  529. '#size' => 20,
  530. '#maxlength' => 255,
  531. ),
  532. 'option' => array(
  533. '#markup' => $option ? (check_plain($option->name) . ' (' . theme('uc_price', array('price' => $option->price)) . ')') : t('n/a'),
  534. ),
  535. 'required' => array(
  536. '#type' => 'checkbox',
  537. '#title' => t('Required'),
  538. '#title_display' => 'invisible',
  539. '#default_value' => $attribute->required,
  540. ),
  541. 'ordering' => array(
  542. '#type' => 'weight',
  543. '#title' => t('List position'),
  544. '#title_display' => 'invisible',
  545. '#delta' => 25,
  546. '#default_value' => $attribute->ordering,
  547. '#attributes' => array('class' => array('uc-attribute-table-ordering')),
  548. ),
  549. 'display' => array(
  550. '#type' => 'select',
  551. '#title' => t('Display'),
  552. '#title_display' => 'invisible',
  553. '#default_value' => $attribute->display,
  554. '#options' => _uc_attribute_display_types(),
  555. ),
  556. );
  557. }
  558. $form['actions'] = array('#type' => 'actions');
  559. $form['actions']['save'] = array(
  560. '#type' => 'submit',
  561. '#value' => t('Save changes'),
  562. '#weight' => -2,
  563. );
  564. }
  565. }
  566. elseif ($view == 'add') {
  567. // Get list of attributes not already assigned to this node or class.
  568. $unused_attributes = array();
  569. $result = db_query("SELECT a.aid, a.name, a.label FROM {uc_attributes} a LEFT JOIN {uc_attribute_options} ao ON a.aid = ao.aid GROUP BY a.aid, a.name, a.label ORDER BY a.name");
  570. foreach ($result as $attribute) {
  571. if (!in_array($attribute->aid, $used_aids)) {
  572. $unused_attributes[$attribute->aid] = $attribute->name;
  573. }
  574. }
  575. $form['add_attributes'] = array(
  576. '#type' => 'checkboxes',
  577. '#title' => t('Attributes'),
  578. '#options' => count($unused_attributes) > 0 ? $unused_attributes : array(t('No attributes left to add.')),
  579. '#disabled' => count($unused_attributes) == 0 ? TRUE : FALSE,
  580. '#weight' => -1,
  581. );
  582. $form['actions'] = array('#type' => 'actions');
  583. $form['actions']['add'] = array(
  584. '#type' => 'submit',
  585. '#value' => t('Add attributes'),
  586. '#suffix' => l(t('Cancel'), $type == 'product' ? 'node/' . $id . '/edit/attributes' : 'admin/store/products/classes/' . $class->pcid . '/attributes'),
  587. '#weight' => 0,
  588. );
  589. }
  590. $form['id'] = array(
  591. '#type' => 'value',
  592. '#value' => $id,
  593. );
  594. $form['type'] = array(
  595. '#type' => 'value',
  596. '#value' => $type,
  597. );
  598. $form['view'] = array(
  599. '#type' => 'value',
  600. '#value' => $view,
  601. );
  602. return $form;
  603. }
  604. /**
  605. * Displays the formatted attribute form.
  606. *
  607. * @param $variables
  608. * An associative array containing:
  609. * - form: A render element representing the form.
  610. *
  611. * @see uc_object_attributes_form()
  612. *
  613. * @ingroup themeable
  614. */
  615. function theme_uc_object_attributes_form($variables) {
  616. $form = $variables['form'];
  617. $output = '';
  618. if ($form['view']['#value'] == 'overview') {
  619. $header = array(t('Remove'), t('Name'), t('Label'), t('Default'), t('Required'), t('List position'), t('Display'));
  620. $rows = array();
  621. foreach (element_children($form['attributes']) as $aid) {
  622. $rows[] = array(
  623. 'data' => array(
  624. drupal_render($form['attributes'][$aid]['remove']),
  625. drupal_render($form['attributes'][$aid]['name']),
  626. drupal_render($form['attributes'][$aid]['label']),
  627. drupal_render($form['attributes'][$aid]['option']),
  628. drupal_render($form['attributes'][$aid]['required']),
  629. drupal_render($form['attributes'][$aid]['ordering']),
  630. drupal_render($form['attributes'][$aid]['display']),
  631. ),
  632. 'class' => array('draggable'),
  633. );
  634. }
  635. drupal_add_tabledrag('uc-attribute-table', 'order', 'sibling', 'uc-attribute-table-ordering');
  636. if ($form['type']['#value'] == 'class') {
  637. $path = url('admin/store/products/classes/' . $form['id']['#value'] . '/attributes/add');
  638. }
  639. elseif ($form['type']['#value'] == 'product') {
  640. $path = url('node/' . $form['id']['#value'] . '/edit/attributes/add');
  641. }
  642. $output = theme('table', array(
  643. 'header' => $header,
  644. 'rows' => $rows,
  645. 'attributes' => array('id' => 'uc-attribute-table'),
  646. 'empty' => t('You must first <a href="!url">add attributes to this !type</a>.', array('!url' => $path, '!type' => $form['type']['#value'])),
  647. ));
  648. }
  649. else {
  650. $output = '<div class="uc-attributes-add-link">';
  651. $output .= t('You may add more attributes <a href="!url">here</a>.', array('!url' => url('admin/store/products/attributes/add')));
  652. $output .= '</div>';
  653. }
  654. $output .= drupal_render_children($form);
  655. return $output;
  656. }
  657. /**
  658. * Form submission handler for uc_object_attributes_form().
  659. *
  660. * @see uc_object_attributes_form()
  661. */
  662. function uc_object_attributes_form_submit($form, &$form_state) {
  663. if ($form_state['values']['type'] == 'product') {
  664. $attr_table = 'uc_product_attributes';
  665. $opt_table = 'uc_product_options';
  666. $id = 'nid';
  667. }
  668. elseif ($form_state['values']['type'] == 'class') {
  669. $attr_table = 'uc_class_attributes';
  670. $opt_table = 'uc_class_attribute_options';
  671. $id = 'pcid';
  672. }
  673. if ($form_state['values']['view'] == 'overview' && is_array($form_state['values']['attributes'])) {
  674. $changed = FALSE;
  675. foreach ($form_state['values']['attributes'] as $aid => $attribute) {
  676. if ($attribute['remove']) {
  677. $remove_aids[] = $aid;
  678. }
  679. else {
  680. $attribute['aid'] = $aid;
  681. $attribute[$id] = $form_state['values']['id'];
  682. drupal_write_record($attr_table, $attribute, array('aid', $id));
  683. $changed = TRUE;
  684. }
  685. }
  686. if (isset($remove_aids)) {
  687. $id_value = $form_state['values']['id'];
  688. $select = db_select('uc_attribute_options', 'ao')
  689. ->fields('ao', array('oid'))
  690. ->condition('ao.aid', $remove_aids, 'IN');
  691. db_delete($opt_table)
  692. ->condition('oid', $select, 'IN')
  693. ->condition($id, $id_value)
  694. ->execute();
  695. db_delete($attr_table)
  696. ->condition($id, $id_value)
  697. ->condition('aid', $remove_aids, 'IN')
  698. ->execute();
  699. if ($form_state['values']['type'] == 'product') {
  700. db_delete('uc_product_adjustments')
  701. ->condition('nid', $id_value)
  702. ->execute();
  703. }
  704. drupal_set_message(format_plural(count($remove_aids), '1 attribute has been removed.', '@count attributes have been removed.'));
  705. }
  706. if ($changed) {
  707. drupal_set_message(t('The changes have been saved.'));
  708. }
  709. }
  710. elseif ($form_state['values']['view'] == 'add') {
  711. foreach (array_filter($form_state['values']['add_attributes']) as $aid) {
  712. // Enable all options for added attributes.
  713. $attribute = uc_attribute_load($aid);
  714. $oid = 0;
  715. if (isset($attribute->options)) {
  716. foreach ($attribute->options as $option) {
  717. $option->$id = $form_state['values']['id'];
  718. drupal_write_record($opt_table, $option);
  719. $option->aid = $aid;
  720. }
  721. // Make the first option (if any) the default.
  722. if ($option = reset($attribute->options)) {
  723. $oid = $option->oid;
  724. }
  725. }
  726. $select = db_select('uc_attributes', 'a')
  727. ->condition('aid', $aid);
  728. $select->addExpression(':id', $id, array(':id' => $form_state['values']['id']));
  729. $select->addField('a', 'aid');
  730. $select->addField('a', 'label');
  731. $select->addField('a', 'ordering');
  732. $select->addExpression(':oid', 'default_option', array(':oid' => $oid));
  733. $select->addField('a', 'required');
  734. $select->addField('a', 'display');
  735. db_insert($attr_table)
  736. ->from($select)
  737. ->execute();
  738. }
  739. $num = count(array_filter($form_state['values']['add_attributes']));
  740. if ($num > 0) {
  741. if ($form_state['values']['type'] == 'product') {
  742. db_delete('uc_product_adjustments')
  743. ->condition('nid', $form_state['values']['id'])
  744. ->execute();
  745. }
  746. drupal_set_message(format_plural($num, '1 attribute has been added.', '@count attributes have been added.'));
  747. }
  748. }
  749. if ($form_state['values']['type'] == 'product') {
  750. if (module_exists('entitycache')) {
  751. cache_clear_all($form_state['values']['id'], 'cache_entity_node');
  752. }
  753. $form_state['redirect'] = 'node/' . $form_state['values']['id'] . '/edit/attributes';
  754. }
  755. else {
  756. $form_state['redirect'] = 'admin/store/products/classes/' . $form_state['values']['id'] . '/attributes';
  757. }
  758. }
  759. /**
  760. * Form to assign and modify attribute options on products or classes.
  761. *
  762. * @see uc_object_options_form_validate()
  763. * @see uc_object_options_form_submit()
  764. * @see theme_uc_object_options_form()
  765. *
  766. * @ingroup forms
  767. */
  768. function uc_object_options_form($form, &$form_state, $object, $type) {
  769. if ($type == 'product') {
  770. $product = $object;
  771. $id = $product->nid;
  772. drupal_set_title($product->title);
  773. $attributes = uc_product_get_attributes($id);
  774. $table = 'uc_product_options';
  775. $id_type = 'nid';
  776. }
  777. elseif ($type == 'class') {
  778. $class = $object;
  779. $id = $class->pcid;
  780. drupal_set_title($class->name);
  781. $attributes = uc_class_get_attributes($id);
  782. $table = 'uc_class_attribute_options';
  783. $id_type = 'pcid';
  784. }
  785. foreach ($attributes as $aid => $attribute) {
  786. $form['attributes'][$aid]['name'] = array(
  787. '#markup' => check_plain($attribute->name),
  788. );
  789. $form['attributes'][$aid]['aid'] = array(
  790. '#type' => 'hidden',
  791. '#value' => $attribute->aid,
  792. );
  793. $form['attributes'][$aid]['ordering'] = array(
  794. '#type' => 'value',
  795. '#value' => $attribute->ordering,
  796. );
  797. $form['attributes'][$aid]['options'] = array('#weight' => 2);
  798. $base_attr = uc_attribute_load($attribute->aid);
  799. if ($base_attr->options) {
  800. $options = array();
  801. $query = db_select('uc_attribute_options', 'ao')
  802. ->fields('ao', array(
  803. 'aid',
  804. 'oid',
  805. 'name',
  806. ));
  807. $query->leftJoin($table, 'po', "ao.oid = po.oid AND po.$id_type = :id", array(':id' => $id));
  808. $query->addField('ao', 'cost', 'default_cost');
  809. $query->addField('ao', 'price', 'default_price');
  810. $query->addField('ao', 'weight', 'default_weight');
  811. $query->addField('ao', 'ordering', 'default_ordering');
  812. $query->fields('po', array(
  813. 'cost',
  814. 'price',
  815. 'weight',
  816. 'ordering',
  817. ))
  818. ->addExpression('CASE WHEN po.ordering IS NULL THEN 1 ELSE 0 END', 'null_order');
  819. $query->condition('aid', $attribute->aid)
  820. ->orderBy('null_order')
  821. ->orderBy('po.ordering')
  822. ->orderBy('default_ordering')
  823. ->orderBy('ao.name');
  824. $result = $query->execute();
  825. foreach ($result as $option) {
  826. $oid = $option->oid;
  827. $options[$oid] = '';
  828. $form['attributes'][$aid]['options'][$oid]['select'] = array(
  829. '#type' => 'checkbox',
  830. '#default_value' => isset($attribute->options[$oid]) ? TRUE : FALSE,
  831. '#title' => check_plain($option->name),
  832. );
  833. $form['attributes'][$aid]['options'][$oid]['cost'] = array(
  834. '#type' => 'uc_price',
  835. '#title' => t('Cost'),
  836. '#title_display' => 'invisible',
  837. '#default_value' => is_null($option->cost) ? $option->default_cost : $option->cost,
  838. '#size' => 6,
  839. '#allow_negative' => TRUE,
  840. );
  841. $form['attributes'][$aid]['options'][$oid]['price'] = array(
  842. '#type' => 'uc_price',
  843. '#title' => t('Price'),
  844. '#title_display' => 'invisible',
  845. '#default_value' => is_null($option->price) ? $option->default_price : $option->price,
  846. '#size' => 6,
  847. '#allow_negative' => TRUE,
  848. );
  849. $form['attributes'][$aid]['options'][$oid]['weight'] = array(
  850. '#type' => 'textfield',
  851. '#title' => t('Weight'),
  852. '#title_display' => 'invisible',
  853. '#default_value' => is_null($option->weight) ? $option->default_weight : $option->weight,
  854. '#size' => 5,
  855. );
  856. $form['attributes'][$aid]['options'][$oid]['ordering'] = array(
  857. '#type' => 'weight',
  858. '#title' => t('List position'),
  859. '#title_display' => 'invisible',
  860. '#delta' => 50,
  861. '#default_value' => is_null($option->ordering) ? $option->default_ordering : $option->ordering,
  862. '#attributes' => array('class' => array('uc-attribute-option-table-ordering')),
  863. );
  864. }
  865. $form['attributes'][$aid]['default'] = array(
  866. '#type' => 'radios',
  867. '#title' => t('Default'),
  868. '#title_display' => 'invisible',
  869. '#options' => $options,
  870. '#default_value' => $attribute->default_option,
  871. );
  872. }
  873. }
  874. if (!empty($form['attributes'])) {
  875. $form['attributes']['#tree'] = TRUE;
  876. $form['actions'] = array('#type' => 'actions');
  877. $form['actions']['submit'] = array(
  878. '#type' => 'submit',
  879. '#value' => t('Submit'),
  880. '#weight' => 10,
  881. );
  882. }
  883. $form['id'] = array(
  884. '#type' => 'value',
  885. '#value' => $id,
  886. );
  887. $form['type'] = array(
  888. '#type' => 'value',
  889. '#value' => $type,
  890. );
  891. return $form;
  892. }
  893. /**
  894. * Displays the option form.
  895. *
  896. * @param $variables
  897. * An associative array containing:
  898. * - form: A render element representing the form.
  899. *
  900. * @see uc_object_options_form()
  901. *
  902. * @ingroup themeable
  903. */
  904. function theme_uc_object_options_form($variables) {
  905. $form = $variables['form'];
  906. $output = '';
  907. drupal_add_js('misc/tableselect.js');
  908. $header = array(array('data' => '&nbsp;&nbsp;' . t('Options'), 'class' => array('select-all')), t('Default'), t('Cost'), t('Price'), t('Weight'), t('List position'));
  909. $tables = 0;
  910. if (isset($form['attributes'])) {
  911. foreach (element_children($form['attributes']) as $key) {
  912. $rows = array();
  913. foreach (element_children($form['attributes'][$key]['options']) as $oid) {
  914. $rows[] = array(
  915. 'data' => array(
  916. drupal_render($form['attributes'][$key]['options'][$oid]['select']),
  917. drupal_render($form['attributes'][$key]['default'][$oid]),
  918. drupal_render($form['attributes'][$key]['options'][$oid]['cost']),
  919. drupal_render($form['attributes'][$key]['options'][$oid]['price']),
  920. drupal_render($form['attributes'][$key]['options'][$oid]['weight']),
  921. drupal_render($form['attributes'][$key]['options'][$oid]['ordering']),
  922. ),
  923. 'class' => array('draggable'),
  924. );
  925. }
  926. $table_id = 'uc-attribute-option-table-' . $tables++;
  927. drupal_add_tabledrag($table_id, 'order', 'sibling', 'uc-attribute-option-table-ordering');
  928. $output .= theme('table', array(
  929. 'header' => $header,
  930. 'rows' => $rows,
  931. 'attributes' => array(
  932. 'class' => array('product_attributes'),
  933. 'id' => $table_id,
  934. ),
  935. 'caption' => '<h2>' . drupal_render($form['attributes'][$key]['name']) . '</h2>',
  936. 'empty' => t('This attribute does not have any options.'),
  937. ));
  938. }
  939. }
  940. if (!$tables) {
  941. if ($form['type']['#value'] == 'product') {
  942. drupal_set_message(t('This product does not have any attributes.'), 'warning');
  943. }
  944. else {
  945. drupal_set_message(t('This product class does not have any attributes.'), 'warning');
  946. }
  947. }
  948. $output .= drupal_render_children($form);
  949. return $output;
  950. }
  951. /**
  952. * Returns a themed set of attribute options for use in order displays.
  953. *
  954. * @param $variables
  955. * An associative array containing:
  956. * - attributes: An associative array containing the set of attributes,
  957. * with each element keyed by attribute ID:
  958. * - <aid>: An associative array containing:
  959. * - #attribute_name: Attribute name.
  960. * - #options: Array of option names.
  961. *
  962. * @return
  963. * Themed set of attribute options.
  964. *
  965. * @ingroup themeable
  966. */
  967. function theme_uc_product_attributes($variables) {
  968. $attributes = $variables['attributes'];
  969. $option_rows = array();
  970. foreach (element_children($attributes) as $key) {
  971. $optionstr = '';
  972. foreach ((array) $attributes[$key]['#options'] as $option) {
  973. // We only need to allow translation from the second option onward
  974. if (empty($optionstr)) {
  975. $optionstr .= $option;
  976. }
  977. else {
  978. $optionstr .= t(', !option', array('!option' => $option));
  979. }
  980. }
  981. if ($optionstr != '') {
  982. $option_rows[$key] = t('@attribute: @option', array('@attribute' => $attributes[$key]['#attribute_name'], '@option' => $optionstr));
  983. }
  984. }
  985. if (!empty($option_rows)) {
  986. return theme('item_list', array('items' => array_values($option_rows), 'attributes' => array('class' => array('product-description'))));
  987. }
  988. return '';
  989. }
  990. /**
  991. * Makes sure that all selected default options are enabled.
  992. *
  993. * @see uc_object_options_form()
  994. * @see uc_object_options_form_submit()
  995. */
  996. function uc_object_options_form_validate($form, &$form_state) {
  997. $error = FALSE;
  998. if (isset($form_state['values']['attributes'])) {
  999. foreach ($form_state['values']['attributes'] as $aid => $attribute) {
  1000. $selected_opts = array();
  1001. if (isset($attribute['options'])) {
  1002. foreach ($attribute['options'] as $oid => $option) {
  1003. if ($option['select'] == 1) {
  1004. $selected_opts[] = $oid;
  1005. }
  1006. }
  1007. }
  1008. if (!empty($selected_opts) && !isset($form['attributes'][$aid]['default']['#disabled']) && !in_array($attribute['default'], $selected_opts)) {
  1009. form_set_error($attribute['default']);
  1010. $error = TRUE;
  1011. }
  1012. }
  1013. }
  1014. if ($error) {
  1015. drupal_set_message(t('All attributes with enabled options must specify an enabled option as default.'), 'error');
  1016. }
  1017. }
  1018. /**
  1019. * Form submission handler for uc_object_options_form().
  1020. *
  1021. * @see uc_object_options_form()
  1022. * @see uc_object_options_form_validate()
  1023. */
  1024. function uc_object_options_form_submit($form, &$form_state) {
  1025. if ($form_state['values']['type'] == 'product') {
  1026. $attr_table = 'uc_product_attributes';
  1027. $opt_table = 'uc_product_options';
  1028. $id = 'nid';
  1029. }
  1030. elseif ($form_state['values']['type'] == 'class') {
  1031. $attr_table = 'uc_class_attributes';
  1032. $opt_table = 'uc_class_attribute_options';
  1033. $id = 'pcid';
  1034. }
  1035. foreach ($form_state['values']['attributes'] as $attribute) {
  1036. if (isset($attribute['default'])) {
  1037. db_update($attr_table)
  1038. ->fields(array(
  1039. 'default_option' => $attribute['default'],
  1040. ))
  1041. ->condition($id, $form_state['values']['id'])
  1042. ->condition('aid', $attribute['aid'])
  1043. ->execute();
  1044. }
  1045. if (isset($attribute['options'])) {
  1046. db_delete($opt_table)
  1047. ->condition($id, $form_state['values']['id'])
  1048. ->condition('oid', array_keys($attribute['options']), 'IN')
  1049. ->execute();
  1050. foreach ($attribute['options'] as $oid => $option) {
  1051. if ($option['select']) {
  1052. $option[$id] = $form_state['values']['id'];
  1053. $option['oid'] = $oid;
  1054. drupal_write_record($opt_table, $option);
  1055. }
  1056. elseif ($form_state['values']['type'] == 'product') {
  1057. $aid = $attribute['aid'];
  1058. $match = 'i:' . $aid . ';s:' . strlen($oid) . ':"' . $oid . '";';
  1059. db_delete('uc_product_adjustments')
  1060. ->condition('nid', $form_state['values']['id'])
  1061. ->condition('combination', '%' . db_like($match) . '%', 'LIKE')
  1062. ->execute();
  1063. }
  1064. }
  1065. }
  1066. }
  1067. drupal_set_message(t('The @type options have been saved.', array('@type' => $form_state['values']['type'] == 'product' ? t('product') : t('product class'))));
  1068. if ($form_state['values']['type'] == 'product') {
  1069. // Clear the page and block caches.
  1070. cache_clear_all();
  1071. }
  1072. }
  1073. /**
  1074. * Form builder: associate option combinations with a product variant's SKU.
  1075. *
  1076. * @see uc_product_adjustments_form_submit()
  1077. *
  1078. * @ingroup forms
  1079. */
  1080. function uc_product_adjustments_form($form, &$form_state, $node) {
  1081. drupal_set_title($node->title);
  1082. $nid = $node->nid;
  1083. // Populate table and such.
  1084. $model = $node->model;
  1085. $query = db_select('uc_product_attributes', 'pa');
  1086. $query->leftJoin('uc_attributes', 'a', 'pa.aid = a.aid');
  1087. $query->leftJoin('uc_attribute_options', 'ao', 'a.aid = ao.aid');
  1088. $query->leftJoin('uc_product_options', 'po', 'ao.oid = po.oid AND po.nid = :po_nid', array(':po_nid' => $nid));
  1089. $result = $query->fields('pa', array('nid', 'aid', 'ordering', 'display'))
  1090. ->fields('a', array('name', 'ordering', 'aid'))
  1091. ->fields('ao', array('aid'))
  1092. ->condition('pa.nid', $nid)
  1093. ->having('COUNT(po.oid) > 0')
  1094. ->groupBy('ao.aid')
  1095. ->groupBy('pa.aid')
  1096. ->groupBy('pa.display')
  1097. ->groupBy('a.name')
  1098. ->groupBy('pa.ordering')
  1099. ->groupBy('a.ordering')
  1100. ->groupBy('pa.nid')
  1101. ->addTag('uc_product_adjustments_form')
  1102. ->execute();
  1103. $i = 1;
  1104. $attribute_names = '';
  1105. $full_attributes = array();
  1106. $values = array();
  1107. $query = db_select('uc_product_options', "po$i")->extend('PagerDefault')
  1108. ->limit(20);
  1109. $attribute_ids = array();
  1110. foreach ($result as $prod_attr) {
  1111. if ($i > 1) {
  1112. $query->join('uc_product_options', "po$i");
  1113. }
  1114. $query->leftJoin('uc_attribute_options', "ao$i", "po$i.oid = ao$i.oid AND po$i.nid = :nid", array(':nid' => $nid));
  1115. $query->addField("ao$i", 'aid', "aid$i");
  1116. $query->addField("ao$i", 'name', "name$i");
  1117. $query->addField("ao$i", 'oid', "oid$i");
  1118. $query->addField("po$i", 'ordering', "ordering$i");
  1119. $query->condition("ao$i.aid", $prod_attr->aid)
  1120. ->orderBy("po$i.ordering")
  1121. ->orderBy("ao$i.name");
  1122. ++$i;
  1123. $attribute_names .= '<th>' . check_plain($prod_attr->name) . '</th>';
  1124. $attribute_ids[] = $prod_attr->aid;
  1125. }
  1126. $num_prod_attr = count($attribute_ids);
  1127. if ($num_prod_attr) {
  1128. // Get previous values.
  1129. $old_vals = db_query("SELECT * FROM {uc_product_adjustments} WHERE nid = :nid", array(':nid' => $nid))->fetchAll();
  1130. $result = $query->execute();
  1131. $form['original'] = array(
  1132. '#markup' => '<p><b>' . t('Default product SKU: @sku', array('@sku' => $model)) . '</b></p>',
  1133. );
  1134. $form['default'] = array(
  1135. '#type' => 'value',
  1136. '#value' => $model,
  1137. );
  1138. $form['table'] = array(
  1139. '#prefix' => '<table class="combinations">',
  1140. '#suffix' => '</table>',
  1141. );
  1142. $form['table']['head'] = array(
  1143. '#markup' => '<thead><tr>' . $attribute_names . '<th>' . t('Alternate SKU') . '</th></tr></thead>',
  1144. '#weight' => 0,
  1145. );
  1146. $form['table']['body'] = array(
  1147. '#prefix' => '<tbody>',
  1148. '#suffix' => '</tbody>',
  1149. '#weight' => 1,
  1150. '#tree' => TRUE,
  1151. );
  1152. $i = 0;
  1153. while ($combo = $result->fetchObject()) {
  1154. $cells = '';
  1155. $row_title = '';
  1156. $comb_array = array();
  1157. for ($j = 1; $j <= $num_prod_attr; ++$j) {
  1158. $cells .= '<td>' . check_plain($combo->{'name' . $j}) . '</td>';
  1159. $row_title .= check_plain($combo->{'name' . $j}) . ', ';
  1160. $comb_array[$combo->{'aid' . $j}] = $combo->{'oid' . $j};
  1161. }
  1162. ksort($comb_array);
  1163. $row_title = substr($row_title, 0, strlen($row_title) - 2);
  1164. $default_model = $model;
  1165. foreach ($old_vals as $ov) {
  1166. if ($ov->combination == serialize($comb_array)) {
  1167. $default_model = $ov->model;
  1168. break;
  1169. }
  1170. }
  1171. $form['table']['body'][$i] = array(
  1172. '#prefix' => '<tr title="' . $row_title . '">',
  1173. '#suffix' => '</tr>',
  1174. );
  1175. $form['table']['body'][$i]['combo'] = array(
  1176. '#markup' => $cells,
  1177. );
  1178. $form['table']['body'][$i]['combo_array'] = array(
  1179. '#type' => 'value',
  1180. '#value' => serialize($comb_array),
  1181. );
  1182. $form['table']['body'][$i]['model'] = array(
  1183. '#type' => 'textfield',
  1184. '#default_value' => $default_model,
  1185. '#prefix' => '<td>',
  1186. '#suffix' => '</td>',
  1187. );
  1188. ++$i;
  1189. }
  1190. $form['nid'] = array(
  1191. '#type' => 'hidden',
  1192. '#value' => $nid,
  1193. );
  1194. $form['actions'] = array('#type' => 'actions');
  1195. $form['actions']['submit'] = array(
  1196. '#type' => 'submit',
  1197. '#value' => t('Submit'),
  1198. );
  1199. }
  1200. else {
  1201. $form['error'] = array(
  1202. '#markup' => '<div><br />' . t('This product does not have any attributes that can be used for SKU adjustments.') . '</div>',
  1203. );
  1204. }
  1205. $form['pager'] = array(
  1206. '#theme' => 'pager',
  1207. );
  1208. return $form;
  1209. }
  1210. /**
  1211. * Form builder for uc_product_adjustments_form().
  1212. *
  1213. * @see uc_product_adjustments_form()
  1214. */
  1215. function uc_product_adjustments_form_submit($form, &$form_state) {
  1216. foreach ($form_state['values']['body'] as $value) {
  1217. if (!empty($value['model']) && $value['model'] != $form_state['values']['default']) {
  1218. db_merge('uc_product_adjustments')
  1219. ->key(array(
  1220. 'nid' => $form_state['values']['nid'],
  1221. 'combination' => $value['combo_array'],
  1222. ))
  1223. ->fields(array(
  1224. 'model' => $value['model'],
  1225. ))
  1226. ->execute();
  1227. }
  1228. else {
  1229. db_delete('uc_product_adjustments')
  1230. ->condition('nid', $form_state['values']['nid'])
  1231. ->condition('combination', $value['combo_array'])
  1232. ->execute();
  1233. }
  1234. }
  1235. drupal_set_message(t('Product adjustments have been saved.'));
  1236. }