uc_attribute.admin.inc 44 KB

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