Functionality exists in D7 version, just need same functionality in d8. Should be easy enough to save and retrieve unfinished orders for each cashier.

Comments

smccabe created an issue. See original summary.

sorabh.v6’s picture

Are you talking about parking of orders as we do in D7 version?

smccabe’s picture

Yes sorry, poor wording on my part, was thinking stash like git stash :P

smccabe’s picture

Also, this patch will probably have to build off this #2911259: Track current POS order session

sorabh.v6’s picture

@smccabe Another question, we will use serialised data or session for storing order data?

smccabe’s picture

@sorabh.v6 you don't need to save any of the data, just the order_id, which can be used to reload the order, see the CurrentOrder stuff that got merged recently that tracks the order ID.

sorabh.v6’s picture

Title: Allow stashing of orders » Allow parking of orders
sorabh.v6’s picture

Assigned: Unassigned » sorabh.v6
sorabh.v6’s picture

@smccabe One last question, should it work on ajax or will it okay without ajax as well?

sorabh.v6’s picture

Assigned: sorabh.v6 » Unassigned
Status: Active » Needs review
StatusFileSize
new3.02 KB

The uploaded patch includes code that shows all parked orders in the pos form. It also allows unparking of particular order by clicking on its button, thereby making the current order to the parked state. Please review.

gauravjeet’s picture

Status: Needs review » Needs work

First of all, a better UX demands the Retrieve Transaction # button be at the top.
I could not really review the patch functionality because of some issues and errors.

A scenario:
- create a POS order from /admin/commerce/pos
- park it from /admin/commerce/orders/5 (, say order id #5)
- now go back to /admin/commerce/pos
- edit the Order items
- hit save on the right >> this will/should/must not create a new order (not sure)
- click Retrieve Transaction #5
- Order #5 could not be retrieved

sorabh.v6’s picture

StatusFileSize
new1.39 MB

@gauravjeet Not sure what you are trying to say. I applied patch on another d8 installation. And did what you mentioned. Its showing no error. And changing state of order from parked to draft. Please see attached gif -

sorabh.v6’s picture

Status: Needs work » Needs review
subhojit777’s picture

Assigned: Unassigned » subhojit777
Status: Needs review » Needs work

The patch on #10 is out dated. Needs reroll. I am going to work on it.

subhojit777’s picture

Assigned: subhojit777 » Unassigned
Status: Needs work » Needs review
StatusFileSize
new3.16 KB

I have made the reroll but haven't tested it yet. I will have to follow the gif as mentioned in #13 and the steps mentioned in #11

subhojit777’s picture

+++ b/src/Form/POSForm.php
@@ -4,6 +4,7 @@ namespace Drupal\commerce_pos\Form;
 use Drupal\Core\Entity\EntityManagerInterface;

This is deprecated. As mentioned by phpstorm.

sorabh.v6’s picture

@subhojit777 Yeah, it's deprecated. EntityTypeManagerInterface should be used instead. But in many places, we have the dependency for the EntityManagerInterface object.

smccabe’s picture

Status: Needs review » Needs work

We're going to need a park button right on the main POS screen, I would add it right between "Add Payment" and 'delete' on page one, use the same styling as "delete"

I would also add it to the payment page, put it after "Finish"

The retrieve parked order button I would probably put at the very top, above the Order Item widget, although only show it if there is at least 1 parked order.

As for the deprecated function, I believe we use that multiple places and we should open a separate issue to get it all at once, since it is not being added by this patch, but already exists for this class.

subhojit777’s picture

Assigned: Unassigned » subhojit777
subhojit777’s picture

StatusFileSize
new1.82 KB
new4.75 KB
subhojit777’s picture

#20 does this:

We're going to need a park button right on the main POS screen, I would add it right between "Add Payment" and 'delete' on page one, use the same styling as "delete"

subhojit777’s picture

Some observations and might be code improvement.

I observed that, after deleting the last/current order, when I revisit the main POS screen, it itself creates a new order. I am not sure where that logic is written.

Since it always creates a new order, then I think this return $order_id ? Order::load($order_id) : NULL inside CurrentOrder::get() can be altered to just return Order::load($order_id).

And this will save multiple current order checks (#20).

  1. +++ b/src/CurrentOrder.php
    @@ -49,4 +49,36 @@ class CurrentOrder {
    +    if ($current_order) {
    

    Duplicate current order check.

  2. +++ b/src/CurrentOrder.php
    @@ -49,4 +49,36 @@ class CurrentOrder {
    +    if ($current_order) {
    

    Duplicate current order check.

subhojit777’s picture

StatusFileSize
new1.15 KB
new5.48 KB

Covers

I would also add it to the payment page, put it after "Finish"

as mentioned in #18

subhojit777’s picture

StatusFileSize
new5.94 KB
new1.78 KB

Covers

The retrieve parked order button I would probably put at the very top, above the Order Item widget, although only show it if there is at least 1 parked order.

as in #18

subhojit777’s picture

Status: Needs work » Needs review
StatusFileSize
new6.58 KB
new649 bytes
subhojit777’s picture

As for the deprecated function, I believe we use that multiple places and we should open a separate issue to get it all at once, since it is not being added by this patch, but already exists for this class.

#2933884: Remove usage of deprecated entity.manager service

subhojit777’s picture

Status: Needs review » Needs work

The last submitted patch, 25: 2911260-25.patch, failed testing. View results

subhojit777’s picture

StatusFileSize
new6.59 KB
new669 bytes
subhojit777’s picture

Status: Needs work » Needs review
subhojit777’s picture

Assigned: subhojit777 » Unassigned
subhojit777’s picture

Do we have to add tests for this parking order feature?

subhojit777’s picture

From #18:

We're going to need a park button right on the main POS screen, I would add it right between "Add Payment" and 'delete' on page one, use the same styling as "delete"

Forgot to mention this -- The park order operation looks like a button, not like the Delete button. The Delete operation is actually, a link, not a button. We can add a custom style, style with class say button--secondary, and there we write styles so that the button looks like a link.

Please move this ticket to Needs work if you think this is necessary.

smccabe’s picture

The button stylings are all over the place in POS and I'm gonna open a separate issue to fix them up all at once and get some consistency.

subhojit777’s picture

And how about this:

Do we have to add tests for this parking order feature?

From #32 @smccabe

smccabe’s picture

Status: Needs review » Needs work

I can hear alexpott in the back of my head, yah we should add tests, probably a derivative of the POSForm test, but specific to this functionality. I wouldn't add more to the POSForm directly, since it is already a very large set of tests and this isn't directly related.

smccabe’s picture

StatusFileSize
new6.53 KB

Small update to this patch to switch the button order so parked is in the correct place. Tests are still needed

subhojit777’s picture

Will work on the failing tests. Then will add some tests supporting the change.

subhojit777’s picture

Assigned: Unassigned » subhojit777
subhojit777’s picture

StatusFileSize
new6.99 KB
new1.07 KB

The problem was introduced here #2901030: Receipt Printing and should have been addressed there itself.

subhojit777’s picture

Re #40:

Sorry. My bad. Not sure whether the problem got introduced in #2901030: Receipt Printing, since the tests are passing there. I tracked it from the commit.

subhojit777’s picture

StatusFileSize
new8.85 KB
new2.09 KB
subhojit777’s picture

+++ b/tests/src/FunctionalJavascript/PosFormTest.php
@@ -309,4 +309,42 @@ class PosFormTest extends JavascriptTestBase {
+    $element = $this->getSession()->getPage()->findAll('xpath', "//input[contains(@id, 'edit-parked-')]");

I was expecting to click the button by value Retrieve Transaction #<order_id> but I couldn't find a way to obtain order id from the test. This can be improved.

subhojit777’s picture

+++ b/src/CurrentOrder.php
@@ -49,4 +49,36 @@ class CurrentOrder {
+  public function isParked() {
...
+  public function park() {

Will add functional tests for these two.

subhojit777’s picture

StatusFileSize
new9.8 KB
new973 bytes

quick cooked up version. Still working on it.

subhojit777’s picture

Assigned: subhojit777 » Unassigned
Status: Needs work » Needs review
StatusFileSize
new3.36 KB
new10.84 KB
alexpott’s picture

I don't think this is working as expected at the moment. When an order is parked we need to create a new order.

  1. +++ b/src/Form/POSForm.php
    @@ -118,6 +131,15 @@ class POSForm extends ContentEntityForm {
    +    if (!$form_state->get('is_parked')) {
    
    @@ -233,6 +255,14 @@ class POSForm extends ContentEntityForm {
    +    if (!$form_state->get('is_parked')) {
    

    I'm not sure that we need this if. Retrieving an order unparks it.

  2. @@ -447,6 +477,22 @@ class POSForm extends ContentEntityForm {
    + $parked_orders = $this->getParkedOrders();
    + if ($parked_orders) {
    + $form['parked'] = [
    + '#type' => 'container',
    + '#weight' => -1,
    + ];
    +
    + foreach ($parked_orders as $parked_order) {
    + $form['parked'][$parked_order] = [
    + '#type' => 'submit',
    + '#value' => t('Retrieve Transaction #@id', ['@id' => $parked_order]),
    + '#submit' => ['::parkedTransactionRetrieve'],
    + ];
    + }
    + }

    It's super weird to list parked orders at the top of the order screen. How did it work before?

  3. +++ b/src/Form/POSForm.php
    @@ -118,6 +131,15 @@ class POSForm extends ContentEntityForm {
    +      $form['actions']['park_order'] = [
    +        '#type' => 'submit',
    +        '#value' => $this->t('Park Order'),
    +        '#weight' => 6,
    +        '#submit' => ['::parkOrder'],
    +      ];
    +    }
    
    @@ -233,6 +255,14 @@ class POSForm extends ContentEntityForm {
    +      $form['actions']['park_order'] = [
    +        '#type' => 'submit',
    +        '#value' => $this->t('Park Order'),
    +        '#submit' => ['::parkOrder'],
    +      ];
    

    Needs '#limit_validation_errors' => [] or we need validation since parking an empty order makes very little sense.

  4. +++ b/src/Form/POSForm.php
    @@ -551,4 +597,44 @@ class POSForm extends ContentEntityForm {
    +  public function parkOrder(array &$form, FormStateInterface $form_state) {
    +    $this->currentOrder->park();
    +  }
    

    I think parking an order should create a new current order. Basically it should call \Drupal\commerce_pos\Form\POSForm::clearOrder().

alexpott’s picture

I've just tried out the D7 functionality and the parked orders can be retrieved from order screen but they appear at the bottom (rather than the top) which makes more sense.

alexpott’s picture

  1. +++ b/src/CurrentOrder.php
    @@ -49,4 +49,36 @@ class CurrentOrder {
    +   * Checks if the current order is parked.
    +   *
    +   * @return bool
    +   *   TRUE if the current order is parked, otherwise FALSE.
    +   */
    +  public function isParked() {
    +    /** @var \Drupal\commerce_order\Entity\OrderInterface $current_order */
    +    $current_order = $this->get();
    +
    +    if ($current_order) {
    +      return $current_order->getState()->getValue()['value'] === 'parked';
    +    }
    +
    +    return FALSE;
    +  }
    +
    +  /**
    +   * Parks the current order.
    +   *
    +   * @throws \Drupal\Core\Entity\EntityStorageException
    +   */
    +  public function park() {
    +    /** @var \Drupal\commerce_order\Entity\OrderInterface $current_order */
    +    $current_order = $this->get();
    +
    +    if ($current_order) {
    +      $current_order->set('state', 'parked')
    +        ->save();
    +    }
    +  }
    

    I don't think this is necessary. PosForm::parkOrder() can set the state and save it. And there's never a reason to call isParked() as far as I can see.

  2. +++ b/src/Form/POSForm.php
    @@ -551,4 +597,44 @@ class POSForm extends ContentEntityForm {
    +    $currentOrder = $this->currentOrder->get();
    +    $currentOrder->set('state', 'parked');
    +    $currentOrder->save();
    

    Should this park an empty order?

subhojit777’s picture

Assigned: Unassigned » subhojit777
subhojit777’s picture

Re #47:

When an order is parked we need to create a new order.

I checked in Drupal 7. There is no new order created after parking an order. The state is changed. The same is happening in Drupal 8.

I'm not sure that we need this if

I am sure I am missing something obvious here. The Park Order button is not supposed to appear if the order is already parked.

It's super weird to list parked orders at the top of the order screen. How did it work before?

Shawn decided to put this at the top. See #18

I think parking an order should create a new current order

I checked the Drupal 7 code. I saw that there the Commerce Order's status is just changed. I do not know whether it is supposed to do it differently in Drupal 8.

Needs '#limit_validation_errors' => [] or we need validation since parking an empty order makes very little sense.

Yeah. Makes sense.


Re #49:

I don't think this is necessary. PosForm::parkOrder() can set the state and save it.

I was trying to expose these as APIs. So that in future if there is a need to check whether CurrentOrder is parked or not, or needs to be parked. Then we can do that from the service itself, rather than calling it from a function.

Should this park an empty order?

Yes. We should put a check here.

subhojit777’s picture

Assigned: subhojit777 » Unassigned
alexpott’s picture

Status: Needs review » Needs work

@subhojit777 in Drupal 7 when you a park an order the current order is cleared and you have a fresh order - otherwise what is the point in parking? I've tested this on https://posdemo.acromedia.com and that is exactly what occurs. Once you have this behaviour then the if's are unnecessary. In order to create a blank order you need to create a new order.

subhojit777’s picture

Assigned: Unassigned » subhojit777
subhojit777’s picture

StatusFileSize
new10.51 KB
new1.89 KB

okay made some changes. Still #47.3 and #49 needs to be addressed.

subhojit777’s picture

Assigned: subhojit777 » Unassigned
+++ b/src/Form/POSForm.php
@@ -581,7 +622,47 @@ class POSForm extends ContentEntityForm {
+    $this->clearOrder();

I still would want to move this inside CurrentOrder::park(), so that the logic is in one place. And any other controller can easily park a current order. Please advice.

alexpott’s picture

  1. +++ b/src/CurrentOrder.php
    @@ -49,4 +49,36 @@ class CurrentOrder {
    +  /**
    +   * Checks if the current order is parked.
    +   *
    +   * @return bool
    +   *   TRUE if the current order is parked, otherwise FALSE.
    +   */
    +  public function isParked() {
    +    /** @var \Drupal\commerce_order\Entity\OrderInterface $current_order */
    +    $current_order = $this->get();
    +
    +    if ($current_order) {
    +      return $current_order->getState()->getValue()['value'] === 'parked';
    +    }
    +
    +    return FALSE;
    +  }
    

    This is now not used by real code.

  2. +++ b/src/CurrentOrder.php
    @@ -49,4 +49,36 @@ class CurrentOrder {
    +  /**
    +   * Parks the current order.
    +   *
    +   * @throws \Drupal\Core\Entity\EntityStorageException
    +   */
    +  public function park() {
    +    /** @var \Drupal\commerce_order\Entity\OrderInterface $current_order */
    +    $current_order = $this->get();
    +
    +    if ($current_order) {
    +      $current_order->set('state', 'parked')
    +        ->save();
    +    }
    +  }
    

    I'm not sure that the CurrentOrder is great class to have. Ideally we'd not have it at all. We'd just use the entity that's already attached to the POSForm. It's state and state introduces a whole interesting class of bugs and we already have form state and we have to keep this in-sync - which introduces another type of bug. Therefore I think we should just ditch this method and do it in the form - this also feels fine because (a) the form is where you interact with parked order (b) the order object already has methods to handle it's state.

subhojit777’s picture

Assigned: Unassigned » subhojit777
subhojit777’s picture

StatusFileSize
new7.91 KB
new3.3 KB

Removed unnecessary code.

subhojit777’s picture

I noticed that retrieval of a parked order is only possible for an empty current order. This is the behavior of Drupal 7. This is not present in the patch.

subhojit777’s picture

Assigned: subhojit777 » Unassigned
Status: Needs work » Needs review
StatusFileSize
new12.64 KB
new7.76 KB
subhojit777’s picture

+++ b/tests/src/FunctionalJavascript/PosFormTest.php
@@ -309,4 +309,67 @@ class PosFormTest extends JavascriptTestBase {
+    $this->getSession()->getPage()->findButton('Park Order')->click();

This works. But still, as a foolproof test, it would have been better if we checked this from the backend as well.

I have checked Commerce core tests, and they mostly rely on data from the db.

smccabe’s picture

StatusFileSize
new29.39 KB

Moved retrieving orders to it's own page, it's cleaner and scales better, plus we can use the order lookup stuff we already added.

I also added a few fields to the Parked Order lookup and backported them to the order lookup.

Tests still need work, not all passing.

Status: Needs review » Needs work

The last submitted patch, 63: 2911260-63.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new20.87 KB
new33.31 KB

Some tidy-ups. I think we need to remove the current order service. We shouldn't need it and using it makes work that we do on this module harder to bring back into the commerce project. All tests pass apart from Drupal\Tests\commerce_pos_receipt\FunctionalJavascript\PosReceiptTest. I can't work out when this patch is causing that to fail (yet).

alexpott’s picture

lolz. The reason Drupal\Tests\commerce_pos_receipt\FunctionalJavascript\PosReceiptTest was failing locally for me was because I had the jQuery.Print library lying around.

alexpott’s picture

StatusFileSize
new3.21 KB
new35.66 KB

Here's just a little bit more tidy up.

  • smccabe committed 4c3c63d on 8.x-2.x authored by subhojit777
    Issue #2911260 by subhojit777, alexpott, smccabe, sorabh.v6: Allow...
smccabe’s picture

Status: Needs review » Fixed

Functionality all looks good, committing. I do have a couple of follow up questions for my own knowledge though.

Why do we need to build this out and not just use the getPage() like normal?

    $out = $this->getSession()->getPage()->getContent();
    $html_output = 'GET request to: ' . $this->getSession()->getCurrentUrl();
    $html_output .= '<hr />' . $out;
    $html_output .= $this->getHtmlOutputHeaders();
    $this->htmlOutput($html_output);

Also, why the change here, is one better than the other?

-    $web_assert->elementContains('css', '#order-lookup-results > div > table > tbody > tr > td:nth-child(1) > a', 1);
-    $web_assert->elementContains('css', '#order-lookup-results > div > table > tbody > tr > td:nth-child(3)', 'Parked');
-    $web_assert->elementContains('css', '#order-lookup-results > div > table > tbody > tr > td:nth-child(7) > a', 'Retrieve');
+    $web_assert->elementContains('xpath', '//*[@id="edit-result"]/table/tbody/tr[2]/td[1]/a', 1);
+    $web_assert->elementContains('xpath', '//*[@id="edit-result"]/table/tbody/tr[2]/td[3]', 'Parked');
+    $web_assert->elementContains('xpath', '//*[@id="edit-result"]/table/tbody/tr[2]/td[7]/a', 'Retrieve');
alexpott’s picture

the first thing is some debug I left in accidentally. I'll remove it with a commit. I just is more useful than a screenshot to see the current page if there are fails - you get the current html.

I converted the css selects to xpath because I found it easier to target the specific row - for some reason #edit-result > table > tbody > tr:nth-child(1) > td:nth-child(7) > a didn't work.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.