freight tracking - saving freight type and tracking code
authorTony Cook <tony@develop-help.com>
Mon, 30 May 2011 00:20:13 +0000 (10:20 +1000)
committerTony Cook <tony@develop-help.com>
Wed, 8 Jun 2011 02:36:19 +0000 (12:36 +1000)
schema/bse.sql
site/cgi-bin/modules/BSE/DB/Mysql.pm
site/cgi-bin/modules/BSE/Request/Base.pm
site/cgi-bin/modules/BSE/TB/Order.pm
site/cgi-bin/modules/BSE/TB/Orders.pm
site/cgi-bin/modules/BSE/UI/AdminShop.pm
site/data/db/bse_msg_base.data
site/data/db/bse_msg_defaults.data
site/templates/admin/order_detail.tmpl
site/util/mysql.str

index 8fbdb3b..977d07a 100644 (file)
@@ -330,6 +330,8 @@ create table orders (
   
   paypal_tran_id varchar(255) null,
 
+  freight_tracking varchar(255) not null default '',
+
   primary key (id),
   index order_cchash(ccNumberHash),
   index order_userId(userId, orderDate)
index 8bac3de..10250de 100644 (file)
@@ -5,7 +5,7 @@ use vars qw/@ISA/;
 use Carp 'confess';
 @ISA = qw(BSE::DB);
 
-our $VERSION = "1.000";
+our $VERSION = "1.001";
 
 use vars qw($VERSION $MAX_CONNECTION_AGE);
 
@@ -153,8 +153,8 @@ SQL
    Orders => 'select * from orders',
    getOrderByPkey => 'select * from orders where id = ?',
    getOrderItemByOrderId => 'select * from order_item where orderId = ?',
-   addOrder => 'insert orders values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
-   replaceOrder => 'replace orders values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   addOrder => 'insert orders values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   replaceOrder => 'replace orders values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    addOrderItem => 'insert order_item values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    replaceOrderItem => 'replace order_item values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    getOrderByUserId => 'select * from orders where userId = ?',
index dbd28cd..d690fd2 100644 (file)
@@ -1012,7 +1012,7 @@ sub audit {
 
   require BSE::TB::AuditLog;
 
-  $opts{actor} ||= $self->user;
+  $opts{actor} ||= $self->user || "U";
 
   return BSE::TB::AuditLog->log(%opts);
 }
index 75dfc74..bbd5ef5 100644 (file)
@@ -6,7 +6,7 @@ use vars qw/@ISA/;
 @ISA = qw/Squirrel::Row/;
 use Carp 'confess';
 
-our $VERSION = "1.001";
+our $VERSION = "1.002";
 
 sub columns {
   return qw/id
@@ -28,7 +28,7 @@ sub columns {
            ccStatus2 ccTranId complete delivOrganization billOrganization
            delivStreet2 billStreet2 purchase_order shipping_method
            shipping_name shipping_trace
-          paypal_token paypal_tran_id/;
+          paypal_token paypal_tran_id freight_tracking/;
 }
 
 sub defaults {
@@ -80,6 +80,7 @@ sub defaults {
      shipping_method => '',
      shipping_name => '',
      shipping_trace => undef,
+     freight_tracking => "",
     );
 }
 
index f726a08..43cef18 100644 (file)
@@ -5,10 +5,32 @@ use vars qw(@ISA $VERSION);
 @ISA = qw(Squirrel::Table);
 use BSE::TB::Order;
 
-our $VERSION = "1.000";
+our $VERSION = "1.002";
 
 sub rowClass {
   return 'BSE::TB::Order';
 }
 
+# shipping methods when we don't automate shipping
+sub dummy_shipping_methods {
+  my $cfg = BSE::Cfg->single;
+
+  my %ship = $cfg->entriesCS("dummy shipping methods");
+  my @ship;
+  for my $key (sort { $ship{$a} cmp $ship{$b} } keys %ship) {
+    my $name = $key;
+    $ship{$key} =~ /,(.*)/ and $name = $1;
+
+    push @ship, { id => $key, name => $name };
+  }
+
+  unshift @ship,
+    {
+     id => "",
+     name => "(None selected)",
+    };
+
+  return @ship;
+}
+
 1;
index eded2c2..632ae72 100644 (file)
@@ -12,14 +12,14 @@ use Constants qw(:shop $SHOPID $PRODUCTPARENT
 use BSE::TB::Images;
 use Articles;
 use BSE::Sort;
-use BSE::Util::Tags qw(tag_hash);
+use BSE::Util::Tags qw(tag_hash tag_error_img);
 use BSE::Util::Iterate;
 use BSE::WebUtil 'refresh_to_admin';
 use BSE::Util::HTML qw(:default popup_menu);
 use BSE::Arrows;
 use BSE::Shop::Util qw(:payment order_item_opts nice_options);
 
-our $VERSION = "1.001";
+our $VERSION = "1.004";
 
 my %actions =
   (
@@ -32,6 +32,7 @@ my %actions =
    order_filled => 'shop_order_filled',
    order_paid => 'shop_order_paid',
    order_unpaid => 'shop_order_unpaid',
+   order_save => 'shop_order_save',
    product_detail => '',
    product_list => '',
    paypal_refund => 'bse_shop_order_refund_paypal',
@@ -570,14 +571,29 @@ sub tag_siteuser {
   return escape_html($value);
 }
 
+sub tag_shipping_method_select {
+  my ($self, $order) = @_;
+
+  my @methods = BSE::TB::Orders->dummy_shipping_methods;
+
+  return popup_menu
+    (
+     -name => "shipping_name",
+     -values => [ map $_->{id}, @methods ],
+     -labels => { map { $_->{id} => $_->{name} } @methods },
+     -id => "shipping_name",
+     -default => $order->shipping_name,
+    );
+}
+
 sub req_order_detail {
-  my ($class, $req, $message) = @_;
+  my ($class, $req, $errors) = @_;
 
   my $cgi = $req->cgi;
   my $id = $cgi->param('id');
   if ($id and
       my $order = BSE::TB::Orders->getByPkey($id)) {
-    $message ||= $cgi->param('m') || '';
+    my $message = $req->message($errors);
     my @lines = $order->items;
     my @products = map { Products->getByPkey($_->{productId}) } @lines;
     my $line_index = -1;
@@ -585,12 +601,12 @@ sub req_order_detail {
     my @options;
     my $option_index = -1;
     my $siteuser;
+    my $it = BSE::Util::Iterate->new;
+
     my %acts;
     %acts =
       (
-       BSE::Util::Tags->basic(\%acts, $cgi, $req->cfg),
-       BSE::Util::Tags->admin(\%acts, $req->cfg),
-       BSE::Util::Tags->secure($req),
+       $req->admin_tags,
        item => sub { escape_html($lines[$line_index]{$_[0]}) },
        iterate_items_reset => sub { $line_index = -1 },
        iterate_items => 
@@ -616,8 +632,17 @@ sub req_order_detail {
        option => sub { escape_html($options[$option_index]{$_[0]}) },
        ifOptions => sub { @options },
        options => sub { nice_options(@options) },
-       message => sub { $message },
+       message => $message,
+       error_img => [ \&tag_error_img, $errors ],
        siteuser => [ \&tag_siteuser, $order, \$siteuser, ],
+       $it->make
+       (
+       single => "shipping_method",
+       plural => "shipping_methods",
+       code => [ dummy_shipping_methods => "BSE::TB::Orders" ],
+       ),
+       shipping_method_select =>
+       [ tag_shipping_method_select => $class, $order ],
       );
 
     return $req->dyn_response('admin/order_detail', \%acts);
@@ -723,6 +748,112 @@ sub req_paypal_refund {
   }
 }
 
+=item order_save
+
+Make changes to an order, only a limited set of fields can be changed.
+
+Parameters:
+
+=over
+
+=item *
+
+id - id of the order.  Required.
+
+=item *
+
+shipping_method - if automated shipping calculations are disabled, the
+id of the dummy shipping method to set for the order.
+
+=item *
+
+freight_tracking - the freight tracking code for the shipment.
+
+=back
+
+Requires csrfp token C<shop_order_save>.
+
+=cut
+
+sub req_order_save {
+  my ($self, $req) = @_;
+
+  $req->check_csrf("shop_order_save")
+    or return $self->req_product_list($req, "Bad or missing csrf token: " . $req->csrf_error);
+
+  my $cgi = $req->cgi;
+  my $id = $cgi->param("id");
+  $id && $id =~ /^[0-9]+$/
+    or return $self->req_product_list($req, "No order id supplied");
+
+  my $order = BSE::TB::Orders->getByPkey($id)
+    or return $self->req_product_list($req, "No such order id");
+
+  my %errors;
+  my $save = 0;
+
+  my $new_freight_tracking = 0;
+  my $code = $cgi->param("freight_tracking");
+  if (defined $code && $code ne $order->freight_tracking) {
+    $order->set_freight_tracking($code);
+    ++$new_freight_tracking;
+    ++$save;
+  }
+
+  my $new_shipping_name = 0;
+  unless ($req->cfg->entry("shop", "shipping", 0)) {
+    my $shipping_name = $cgi->param("shipping_name");
+    if (defined $shipping_name
+       && $shipping_name ne $order->shipping_name) {
+      my @ship = BSE::TB::Orders->dummy_shipping_methods();
+      my ($entry) = grep $_->{id} eq $shipping_name, @ship;
+      if ($entry) {
+       $order->set_shipping_name($entry->{id});
+       $order->set_shipping_method($entry->{name});
+       ++$new_shipping_name;
+       ++$save;
+      }
+      else {
+       $errors{shipping_method} = "msg:bse/admin/shop/saveorder/badmethod:$shipping_name";
+      }
+    }
+  }
+
+  keys %errors
+    and return $self->req_order_detail($req, \%errors);
+
+  if ($save) {
+    $order->save;
+    $req->flash("msg:bse/admin/shop/saveorder/saved");
+
+    if ($new_freight_tracking) {
+      $req->audit
+       (
+        component => "shopadmin:orders:saveorder",
+        object => $order,
+        msg => "New freight tracking code set: '" . $order->freight_tracking . "'",
+        level => "info",
+       );
+    }
+    if ($new_shipping_name) {
+      $req->audit
+       (
+        component => "shopadmin:orders:saveorder",
+        object => $order,
+        msg => "New shippping method set: '" . $order->shipping_name . "/" . $order->shipping_method . "'",
+        level => "info",
+       );
+    }
+  }
+  else {
+    $req->flash("msg:bse/admin/shop/saveorder/nochanges");
+  }
+
+  my $url = $cgi->param("r") || $req->url("shopadmin", { a_order_detail => 1, id => $order->id });
+
+  return $req->get_refresh($url);
+}
+
 #####################
 # utilities
 # perhaps some of these belong in a class...
index c26e06f..2d07bd4 100644 (file)
@@ -41,6 +41,21 @@ description: Article editor messages
 id: bse/admin/edit/uplabelsect
 description: label in parent list to make article a section
 
+id: bse/admin/shop/
+description: Shop Administration
+
+id: bse/admin/shop/saveorder/
+description: Save changes to an order
+
+id: bse/admin/shop/saveorder/saved
+description: Displayed on a successful save with some changes
+
+id: bse/admin/shop/saveorder/nochanges
+description: Displayed on a save that makes no changes
+
+id: bse/admin/shop/saveorder/badmethod
+description: Invalid shipping method
+
 id: test/
 description: <<TEXT
 Test category
index b086ff1..e5b732f 100644 (file)
@@ -1,5 +1,5 @@
 ---
-# VERSION=1.000
+# VERSION=1.001
 # defaults for the following
 language_code: en
 priority: 0
@@ -34,6 +34,15 @@ message: Unknown language code - no entry found in [languages]
 id: bse/admin/message/badmultiline
 message: Message $1:s may contain only a single line of text
 
+id: bse/admin/shop/saveorder/saved
+message: Order saved successfully
+
+id: bse/admin/shop/saveorder/nochanges
+message: No changes to save
+
+id: bse/admin/shop/saveorder/badmethod
+message: Unknown shipping method '$1:s'
+
 id: bse/shop/cart/empty
 message: Cart emptied
 
index a18066c..0cb220b 100644 (file)
@@ -74,7 +74,7 @@
 </tr>
 <:iterator begin items:>
         <tr> 
-          <td width="100%"><:ifOr [ifEq [item productId] -1] [ifEq [product id] ""]:><:item title:> (product deleted)<:or:><a href="<:script:>?product_detail=1&amp;id=<:product id:>"><:product
+          <td width="100%"><:ifOr [ifEq [item productId] -1] [ifEq [product id] ""]:><:item title:> (product deleted)<:or:><a href="<:adminurl shopadmin product_detail 1 id [product id]:>"><:product
             title:></a><:eif:> <:options:></td>
           <td align=center nowrap><:item units:></td>
           <td align=right nowrap><:money item price:></td>
           <td align=right nowrap><:extension gst:></td>
 </tr>
 <:iterator end items:>
+<:if Cfg shop shipping:>
 <:if Order shipping_name:>
 
         <tr> 
-          <td colspan=3 align=right>
+          <td colspan=3>
 <:if Eq [order shipping_name] "contact":>
 <b>Contact customer to make shipping arrangements</b>
 <:or Eq:>
-Shipping via <:order shipping_method:>:
-<:eif Eq:>
+Shipping via <:order shipping_method:>
+<:eif Eq:>, 
+               <form method="post" action="<:adminurl shopadmin a_order_save 1:>">
+    <input type="hidden" name="id" value="<:order id:>" />
+    <:csrfp shop_order_save hidden:>
+    <label>tracking code: <input type="text" name="freight_tracking" value="<:order freight_tracking:>" /></label>
+    <input type="submit" name="a_order_save" value="Save" />
+    </form>
+
 </td>
           <td align=right nowrap><:money order shipping_cost:></td>
           <td>&nbsp;</td>
@@ -102,6 +110,8 @@ Shipping via <:order shipping_method:>:
           <td align=right nowrap></td>
 </tr>
 <:or Order:><:eif Order:>
+<:or Cfg:>
+<:eif Cfg:>
         <tr bgcolor="#FFFFFF"> 
           <td colspan=3 align=right>Total:</td>
           <td align=right nowrap><:money order total:></td>
@@ -110,6 +120,20 @@ Shipping via <:order shipping_method:>:
           <td>&nbsp;</td>
           <td align=right nowrap><:money order gst:></td>
 </tr>
+<:if Cfg shop shipping:><:or Cfg:>
+<tr>
+  <td colspan="3">
+    <form method="post" action="<:adminurl shopadmin a_order_save 1:>">
+    <input type="hidden" name="id" value="<:order id:>" />
+    <:csrfp shop_order_save hidden:>
+    <label>Shipping method: <:shipping_method_select:></label>
+    <label>tracking code: <input type="text" name="freight_tracking" value="<:order freight_tracking:>" /></label>
+    <input type="submit" name="a_order_save" value="Save" />
+    </form>
+  </td>
+  <td colspan="5"></td>
+</tr>
+<:eif Cfg:>
 </table>
 <:switch:>
 <:case Eq [order paidFor] "0":>
index f64cce4..b8c9ced 100644 (file)
@@ -546,6 +546,7 @@ Column shipping_name;varchar(40);NO;;
 Column shipping_trace;text;YES;NULL;
 Column paypal_token;varchar(255);YES;NULL;
 Column paypal_tran_id;varchar(255);YES;NULL;
+Column freight_tracking;varchar(255);NO;;
 Index PRIMARY;1;[id]
 Index order_cchash;0;[ccNumberHash]
 Index order_userId;0;[userId;orderDate]