diff --git a/shipping/uc_shipping/uc_shipping.info b/shipping/uc_shipping/uc_shipping.info index c1143bf..3dc14cc 100644 --- a/shipping/uc_shipping/uc_shipping.info +++ b/shipping/uc_shipping/uc_shipping.info @@ -3,3 +3,7 @@ description = Gets products ready for physical shipment. dependencies[] = uc_quote package = Ubercart - core (optional) core = 7.x + +; Views handlers +files[] = views/uc_shipping_handler_field_shipment_id.inc +files[] = views/uc_shipping_handler_field_package_weight.inc diff --git a/shipping/uc_shipping/uc_shipping.install b/shipping/uc_shipping/uc_shipping.install index 16b4480..e76ba90 100644 --- a/shipping/uc_shipping/uc_shipping.install +++ b/shipping/uc_shipping/uc_shipping.install @@ -223,6 +223,9 @@ function uc_shipping_schema() { 'foreign keys' => array( 'order_id' => array('uc_orders' => 'order_id'), ), + 'indexes' => array( + 'order_id' => array('order_id'), + ), ); $schema['uc_packages'] = array( @@ -261,7 +264,7 @@ function uc_shipping_schema() { 'not null' => FALSE, ), 'width' => array( - 'description' => 'The pacakge width.', + 'description' => 'The package width.', 'type' => 'float', 'not null' => FALSE, ), @@ -285,7 +288,7 @@ function uc_shipping_schema() { 'default' => 0.0, ), 'sid' => array( - 'description' => 'The {uc_shimpents}.sid, if the package has been shipped.', + 'description' => 'The {uc_shipments}.sid, if the package has been shipped.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, @@ -310,6 +313,10 @@ function uc_shipping_schema() { 'sid' => array('uc_shipments' => 'sid'), 'label_image' => array('file' => 'fid'), ), + 'indexes' => array( + 'order_id' => array('order_id'), + 'sid' => array('sid'), + ), ); $schema['uc_packaged_products'] = array( @@ -342,6 +349,9 @@ function uc_shipping_schema() { 'package_id' => array('uc_packages' => 'package_id'), 'order_product_id' => array('uc_order_products' => 'order_product_id'), ), + 'indexes' => array( + 'order_product_id' => array('order_product_id'), + ), ); return $schema; @@ -447,3 +457,18 @@ function uc_shipping_update_7001() { )); } } + +/** + * Add indexes to package and shipment tables. + */ +function uc_shipping_update_7300() { + // Alter {uc_shipments} table. + db_add_index('uc_shipments', 'order_id', array('order_id')); + + // Alter {uc_packages} table. + db_add_index('uc_packages', 'order_id', array('order_id')); + db_add_index('uc_packages', 'sid', array('sid')); + + // Alter {uc_packaged_products} table. + db_add_index('uc_packaged_products', 'order_product_id', array('order_product_id')); +} diff --git a/shipping/uc_shipping/uc_shipping.module b/shipping/uc_shipping/uc_shipping.module index 0a15bb0..b8bc2c4 100644 --- a/shipping/uc_shipping/uc_shipping.module +++ b/shipping/uc_shipping/uc_shipping.module @@ -766,3 +766,54 @@ function uc_shipping_address_form($form, &$form_state, $addresses, $order) { ); return $form; } + +/** + * Implements hook_views_api(). + */ +function uc_shipping_views_api() { + return array( + 'api' => '2.0', + 'path' => drupal_get_path('module', 'uc_shipping') . '/views', + ); +} + +/** + * Implements hook_date_views_tables(). + */ +function uc_shipping_date_views_tables() { + return array('uc_shipments'); +} + +/** + * Implements hook_date_views_fields(). + * + * All modules that create custom fields that use the + * 'views_handler_field_date' handler can provide + * additional information here about the type of + * date they create so the date can be used by + * the Date API views date argument and date filter. + */ +function uc_shipping_date_views_fields($field) { + $values = array( + // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME. + 'sql_type' => DATE_UNIX, + // Timezone handling options: 'none', 'site', 'date', 'utc' . + 'tz_handling' => 'site', + // Needed only for dates that use 'date' tz_handling. + 'timezone_field' => '', + // Needed only for dates that use 'date' tz_handling. + 'offset_field' => '', + // Array of "table.field" values for related fields that should be + // loaded automatically in the Views SQL. + 'related_fields' => array(), + // Granularity of this date field's db data. + 'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'), + ); + + switch ($field) { + case 'uc_shipments.ship_date': + case 'uc_shipments.expected_delivery': + case 'uc_shipments.changed': + return $values; + } +} diff --git a/shipping/uc_shipping/views/uc_shipping.views.inc b/shipping/uc_shipping/views/uc_shipping.views.inc new file mode 100644 index 0000000..8ac41bb --- /dev/null +++ b/shipping/uc_shipping/views/uc_shipping.views.inc @@ -0,0 +1,568 @@ + t('Shipment ID'), + 'help' => t('The shipment ID.'), + 'field' => array( + 'handler' => 'uc_shipping_handler_field_shipment_id', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_numeric', + 'name field' => 'title', + 'numeric' => TRUE, + 'validate type' => 'sid', + ), + ); + + // Shipment relationship for order + $data['uc_orders']['shipments'] = array( + 'relationship' => array( + 'title' => t('Shipments'), + 'help' => t('Relate shipments to an order. This relationship will create one record for each shipment.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_shipments', + 'base field' => 'order_id', + 'relationship field' => 'order_id', + 'label' => t('shipment'), + ), + ); + + // Carrier field + $data['uc_shipments']['carrier'] = array( + 'title' => t('Carrier'), + 'help' => t('The company making the delivery.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + + // Shipment Transaction ID field + $data['uc_shipments']['transaction_id'] = array( + 'title' => t('Transaction ID'), + 'help' => t("The carrier's shipment identifier."), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + // Shipment Tracking Number field + $data['uc_shipments']['tracking_number'] = array( + 'title' => t('Tracking number'), + 'help' => t('The number used by the carrier to locate the shipment while it is in transit.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + $data['uc_shipments']['ship_date'] = array( + 'title' => t('Ship date'), + 'help' => t('The date when the shipment left the origin address.'), + 'field' => array( + 'handler' => 'views_handler_field_date', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort_date', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_date', + ), + ); + + $data['uc_shipments']['expected_delivery'] = array( + 'title' => t('Expected delivery date'), + 'help' => t('The expected date of delivery.'), + 'field' => array( + 'handler' => 'views_handler_field_date', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort_date', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_date', + ), + ); + + $data['uc_shipments']['changed'] = array( + 'title' => t('Last modified'), + 'help' => t('The time the shipment was last modified.'), + 'field' => array( + 'handler' => 'views_handler_field_date', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort_date', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_date', + ), + ); + + $data['uc_shipments']['cost'] = array( + 'title' => t('Cost'), + 'help' => t('The cost of the shipment.'), + 'field' => array( + 'handler' => 'uc_order_handler_field_money_amount', + 'click sortable' => TRUE, + 'float' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + ); + + $addresses = array( + 'o' => t('Origin address'), + 'd' => t('Delivery address'), + ); + + $fields = array( + 'first_name' => t('First name'), + 'last_name' => t('Last name'), + 'company' => t('Company'), + 'street1' => t('Street address 1'), + 'street2' => t('Street address 2'), + 'city' => t('City'), + 'postal_code' => t('Postal code'), + ); + + foreach ($addresses as $prefix => $address) { + $group = t('Shipment') . ': ' . $address; + + foreach ($fields as $field => $label) { + $data['uc_shipments'][$prefix . '_' . $field] = array( + 'group' => $group, + 'title' => $label, + 'help' => t('The !field of the !address of the shipment.', array('!field' => drupal_strtolower($label), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + } + // uc_order is required by shipping module so is safe to use uc_order handler + $data['uc_shipments'][$prefix . '_full_name'] = array( + 'group' => $group, + 'title' => t('Full name'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('full name'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'additional fields' => array( + $prefix . '_first_name', + $prefix . '_last_name' + ), + 'handler' => 'uc_order_handler_field_order_fullname', + 'prefix' => $prefix, + ), + ); + + $data['uc_shipments_' . $prefix . '_countries']['table']['group'] = $group; + $data['uc_shipments_' . $prefix . '_countries']['table']['join']['uc_shipments'] = array( + 'table' => 'uc_countries', + 'left_field' => $prefix . '_country', + 'field' => 'country_id', + ); + $data['uc_shipments_' . $prefix . '_countries']['country_id'] = array( + 'title' => t('ISO country code (numeric)'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('numeric ISO country code'), '!address' => drupal_strtolower($address))), + 'argument' => array( + 'handler' => 'views_handler_argument_numeric', + 'name field' => 'country_iso_code_2', + 'numeric' => TRUE, + 'validate type' => 'country_id', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + ); + $data['uc_shipments_' . $prefix . '_countries']['country_name'] = array( + 'title' => t('Country'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('country name'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + $data['uc_shipments_' . $prefix . '_countries']['country_iso_code_2'] = array( + 'title' => t('ISO country code (2 characters)'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('ISO country code'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + $data['uc_shipments_' . $prefix . '_countries']['country_iso_code_3'] = array( + 'title' => t('ISO country code (3 characters)'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('ISO country code'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + + $data['uc_shipments_' . $prefix . '_zones']['table']['group'] = $group; + $data['uc_shipments_' . $prefix . '_zones']['table']['join']['uc_shipments'] = array( + 'table' => 'uc_zones', + 'left_field' => $prefix . '_zone', + 'field' => 'zone_id', + ); + $data['uc_shipments_' . $prefix . '_zones']['zone_name'] = array( + 'title' => t('State/Province'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('state or province'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + $data['uc_shipments_' . $prefix . '_zones']['zone_code'] = array( + 'title' => t('State/Province code'), + 'help' => t('The !field of the !address of the shipment.', array('!field' => t('state or province code'), '!address' => drupal_strtolower($address))), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + } + + // Expose packages + $data['uc_packages']['table']['group'] = t('Package'); + + // Package ID field. + // We don't redirect to the shippment page because a package can exists without a shippment. + $data['uc_packages']['package_id'] = array( + 'title' => t('Package ID'), + 'help' => t('The package ID.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_numeric', + 'name field' => 'title', + 'numeric' => TRUE, + 'validate type' => 'sid', + ), + ); + + // Expose packages to their order as a relationship. + // Packages can exists without a shipment so this relationship may be useful. + $data['uc_orders']['packages'] = array( + 'relationship' => array( + 'title' => t('Packages'), + 'help' => t('Relate packages to an order. This relationship will create one record for each package of an order.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_packages', + 'base field' => 'order_id', + 'relationship field' => 'order_id', + 'label' => t('package'), + ), + ); + // Shipment type field + $data['uc_packages']['shipping_type'] = array( + 'title' => t('Shipment type'), + 'help' => t('The basic type of shipment, e.g.: small package, freight, etc.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + + // Package type + $data['uc_packages']['pkg_type'] = array( + 'title' => t('Package type'), + 'help' => t('The type of packaging.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + + // Package value + $data['uc_packages']['value'] = array( + 'title' => t('Value'), + 'help' => t('The monetary value of the package contents.'), + 'field' => array( + 'handler' => 'uc_order_handler_field_money_amount', + 'click sortable' => TRUE, + 'float' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + ); + + // Expose packages to their shipment as a relationship. + $data['uc_shipments']['packages'] = array( + 'relationship' => array( + 'title' => t('Packages'), + 'help' => t('Relate packages to a shipment. This relationship will create one record for each shipped package.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_packages', + 'base field' => 'sid', + 'relationship field' => 'sid', + 'label' => t('package'), + ), + ); + + // Expose shipment to their packages as a relationship. + $data['uc_packages']['shipments'] = array( + 'relationship' => array( + 'title' => t('Shipment'), + 'help' => t('Relate shipment to package.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_packages', + 'base field' => 'sid', + 'relationship field' => 'sid', + 'label' => t('shipment'), + ), + ); + + // Shipment Tracking Number field. + $data['uc_packages']['tracking_number'] = array( + 'title' => t('Tracking number'), + 'help' => t('The number used by the carrier to locate the package while it is in transit.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + // Package length field + $data['uc_packages']['length'] = array( + 'title' => t('Length'), + 'help' => t('The physical length.'), + 'field' => array( + 'additional fields' => array( + 'field' => 'length_units', + ), + 'handler' => 'uc_product_handler_field_length', + 'click sortable' => TRUE, + 'float' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_float', + ), + ); + + // Package width field + $data['uc_packages']['width'] = array( + 'title' => t('Width'), + 'help' => t('The physical width.'), + 'field' => array( + 'additional fields' => array( + 'field' => 'length_units', + ), + 'handler' => 'uc_product_handler_field_length', + 'click sortable' => TRUE, + 'float' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_float', + ), + ); + + // Package height field + $data['uc_packages']['height'] = array( + 'title' => t('Height'), + 'help' => t('The physical height.'), + 'field' => array( + 'additional fields' => array( + 'field' => 'length_units', + ), + 'handler' => 'uc_product_handler_field_length', + 'click sortable' => TRUE, + 'float' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_float', + ), + ); + + // Package weight field + $data['uc_packages']['weight'] = array( + 'title' => t('Weight'), + 'help' => t('The physical weight of package.'), + 'field' => array( + 'additional fields' => array( + 'package_id', + ), + 'handler' => 'uc_shipping_handler_field_package_weight', + 'click sortable' => FALSE, + 'float' => TRUE, + ), + ); + + // Expose packaged products on their package as a relationship. + $data['uc_packages']['packaged_products'] = array( + 'relationship' => array( + 'title' => t('Products'), + 'help' => t('Relate packaged products to a package. This relationship will create one record for each packaged product.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_packaged_products', + 'base field' => 'package_id', + 'relationship field' => 'package_id', + 'label' => t('product'), + ), + ); + + // Expose packaged products + $data['uc_packaged_products']['table']['group'] = t('Package: Product'); + + // Expose packaged products to the ordered product as a relationship. + // By using a relation and not expose fields directly we make sure that + // when ordered products will be fieldable entities all their custom fields, + // the one not stored in the schema, will get loaded. + $data['uc_packaged_products']['uc_order_products'] = array( + 'relationship' => array( + 'title' => t('Ordered product'), + 'help' => t('Relate packaged product to the ordered product.'), + 'handler' => 'views_handler_relationship', + 'base' => 'uc_order_products', + 'base field' => 'order_product_id', + 'relationship field' => 'order_product_id', + 'label' => t('ordered product'), + ), + ); + + // Packaged quantity field + $data['uc_packaged_products']['qty'] = array( + 'title' => t('Quantity'), + 'help' => t('The quantity packaged.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + ); + + return $data; +} diff --git a/shipping/uc_shipping/views/uc_shipping_handler_field_package_weight.inc b/shipping/uc_shipping/views/uc_shipping_handler_field_package_weight.inc new file mode 100644 index 0000000..f414cd0 --- /dev/null +++ b/shipping/uc_shipping/views/uc_shipping_handler_field_package_weight.inc @@ -0,0 +1,46 @@ +ensure_my_table(); + $this->add_additional_fields(); + } + + /** + * Overrides uc_product_handler_field_weight::render(). + */ + function render($values) { + $package = uc_shipping_package_load($values->{$this->aliases['package_id']}); + + if ($this->options['format'] == 'numeric') { + return $package->weight; + } + + if ($this->options['format'] == 'uc_weight') { + return uc_weight_format($package->weight, $package->weight_units); + } + } +} diff --git a/shipping/uc_shipping/views/uc_shipping_handler_field_shipment_id.inc b/shipping/uc_shipping/views/uc_shipping_handler_field_shipment_id.inc new file mode 100644 index 0000000..6a8950b --- /dev/null +++ b/shipping/uc_shipping/views/uc_shipping_handler_field_shipment_id.inc @@ -0,0 +1,78 @@ +options['link_to_shipment'])) { + $this->additional_fields['order_id'] = array('table' => 'uc_shipments', 'field' => 'order_id'); + } + } + + /** + * Overrides views_handler::option_definition(). + */ + function option_definition() { + $options = parent::option_definition(); + $options['link_to_shipment'] = array('default' => FALSE); + return $options; + } + + /** + * Overrides views_handler::options_form(). + * + * Provides link to shipment administration page. + */ + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + $form['link_to_shipment'] = array( + '#title' => t('Link this field to the shipment page'), + '#description' => t('This will override any other link you have set.'), + '#type' => 'checkbox', + '#default_value' => !empty($this->options['link_to_shipment']), + ); + } + + /** + * Renders whatever the data is as a link to the order. + * + * Data should be made XSS safe prior to calling this function. + */ + function render_link($data, $values) { + if (!empty($this->options['link_to_shipment'])) { + $this->options['alter']['make_link'] = FALSE; + + if (user_access('fulfill orders')) { + $path = 'admin/store/orders/' . $this->get_value($values, 'order_id') . '/shipments/' . $values->{$this->field_alias}; + } + else { + $path = FALSE; + } + + if ($path && $data !== NULL && $data !== '') { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = $path; + } + } + return $data; + } + + /** + * Overrides views_handler_field::render(). + */ + function render($values) { + return $this->render_link(check_plain($values->{$this->field_alias}), $values); + } + +}