X-Cart: shopping cart software

X-Cart forums (https://forum.x-cart.com/index.php)
-   Dev Questions (X-Cart 5) (https://forum.x-cart.com/forumdisplay.php?f=56)
-   -   "Fake" orders (or how do a cart become an order ?) (https://forum.x-cart.com/showthread.php?t=77214)

Ed B. 09-26-2019 12:51 AM

"Fake" orders (or how do a cart become an order ?)
 
I would like to create a "fake checkout page" so that a "fake order" can be placed. To be more precise, the fake orders will have all "properties" that the real orders have, but they don't trigger the actions that real orders do, except being saved in the database, and they shouldn't show up in the order list.

It looks like all I would need is to save the order with the property is_order set to 0.
However, I have no idea on how to achieve this.

What I have figured out so far is that when one places an order, doActionCheckout()
function in the controller class is called. Which in turn calls the function registerOrderPackaging( , ) from Core/OrderHistory.php. This function, in turn, calls for
registerPlaceOrder, registerEvent which somehow register the order event in the
xc_order_history_events table. But I don't see exactly how the order is saved in xc_orders table. So my first question is: is there any way to save a "fake order" placed on "fake" ckeckout page in the table with is_order=0?


Otherwise, I have so far succeeded to decorate the /Model/Order.php class so that it
has a new column "is_fake", and "fake orders" have is_fake set to 1. Unfortunately I can't set is_order=0 this way because getCart() has no such property as is_order.
So another way to achieve my goal would be to decorate all classes involving the treatment of orders (like email notification, admin order list, customer order list etc.) ignore the orders with the property is_fake = 1. But to start with, how do I find complete set of such classes?


Thank you very much in advance.

cflsystems 09-26-2019 05:17 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
This is where an IDE can help a lot...


Search for "is_order" shows this in classes/XLite/Model/Repo/Cart.php




Code:

/**
    * Define query for markAsOrder() method
    *
    * @paraminteger $orderId Order id
    *
    * @return \Doctrine\DBAL\Statement|void
    */
protectedfunctiondefineMarkAsOrderQuery($orderId)
    {
$stmt = $this->_em->getConnection()->prepare(
'UPDATE'.$this->_class->getTableName() .' '
.'SET is_order = :flag '
.'WHERE order_id = :id'
        );

if ($stmt) {
$stmt->bindValue(':flag', 1);
$stmt->bindValue(':id', $orderId);

        } else {
$stmt = null;
        }

return$stmt;
    }





And in classes/XLite/Model/Repo/Order.php


Code:

/**
    * Define query for markAsCart() method
    *
    * @paraminteger $orderId Order id
    *
    * @return \Doctrine\DBAL\Statement|void
    */
protectedfunctiondefineMarkAsCartQuery($orderId)
    {
$stmt = $this->_em->getConnection()->prepare(
'UPDATE'.$this->_class->getTableName() .' '
.'SET is_order = :flag '
.'WHERE order_id = :id'
        );

if ($stmt) {
$stmt->bindValue(':flag', 0);
$stmt->bindValue(':id', $orderId);

        } else {
$stmt = null;
        }

return$stmt;
    }


Ed B. 09-28-2019 12:04 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
Thank you very much. O.K, I got that
There is a function markAsOrder in the Model/Repo/Cart.php
which is used in Model/Cart.php
Code:

    /**
    * Mark cart as order
    *
    * @return void
    */
    public function markAsOrder()
    {
        parent::markAsOrder();

        if ($this instanceof \XLite\Model\Cart) {
            $this->assignOrderNumber();
        }

        $this->getRepository()->markAsOrder($this->getOrderId());
    }


which in turn is called in Model/Order.php

Code:

    public function processSucceed()
    {
        $this->markAsOrder();
....



So I presume I only would have to modify somewhere in the chain the value of is_order, I am done? And probably the simplest thing is to decorate Model/Order.php to have something like
Code:

    public function processSucceed()
    {
        if (!isFake()) {
        $this->markAsOrder();
          }
    ....

And maybe to be on the safe side, I can add couple of lines to set is_order=0 when I have a fake order?

Ed B. 09-29-2019 09:03 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
Actually things doesn't go that easy. Any attempt to override the function processSuceed() in \XLite\Model\Order from \Vendor\Module\Model\Order ends up with an internal server error. I can't even do
Code:

public function processSucceed()
{
parent::processSuceed();
}



Any ideas?

cflsystems 09-29-2019 09:50 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
You are not doing something right with the file then. Internal server error will indicate an error with the file itself or php syntax not with the execution of the function.


Example - If it works for QT it should work for you too - classes/XLite/Module/CDev/Coupons/Model/Order.php


Code:

/**
    * Called when an order successfully placed by a client
    *
    * @return void
    */
public function processSucceed()
{
parent::processSucceed();

foreach ($this->getUsedCoupons() as $usedCoupons) {
$usedCoupons->markAsUsed();
}
}


Ed B. 10-01-2019 11:34 PM

Re: "Fake" orders (or how do a cart become an order ?)
 
Thank you very much, I really should "reread" my codes (well, I did, lots of times). It was a matter of misplaced braces.


So, somehow I can't do things like
Code:

public function markAsOrder()
{
if (isfake)
{parent::markAsCart();}
else
  parent::markAsOrder();
}

, this leading to an error (no such property, function name must start...)


Thus I had to reproduce the entire processSucceed function with the if clause
at the beginning. In any case, it works like a charm. Now my question is, why does this work in the first place? For example, how come we don't see these fake orders in order list page?


The order list page in the admin area uses the widget XLite/View/ItemsList/Model/Order/Admin/Search.php. This class, contains nothing about the property is_order. I also noticed that when is_order=0, there is no orderNumber, but then again, this property is used everywhere to sort orders, but there is no search condition that requires orderNumber not to be null. I saw that in the class Model/Repo/Order.php
"alternativeIdentifier" is defined to be orderNumber, so I deorated in Module/Vendor/Repo/Order.php
Code:

<?php
namespace XLite\Module\Vendor\Module\Model\Repo
abstract class Order extends \XLite\Model\Repo\Order implements \XLite\Base\IDecorator

{
protected $alternativeIdentifier = array(
        array('orderId'),
    );

}

but no fake orders are shown in the list. So, what is going on?


If I wanted to fake orders in the order list among the real ones, what would I have to do? It is not that I need, but this mystery really bothers me.

cflsystems 10-02-2019 05:35 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
That's tricky and related to Doctrine. While I am not 100% (almost 100% sure though) sure this is how XC determines which records are orders and which are not - is_order = 1 for placed orders


The Repo Order class when creating the query builder uses "placedOnly" parameter. Search the class fot it and you will see how it adds condition to select only records that are an instance of Order.


The Model Order class has these Doctrine annotations
@DiscriminatorColumn
@DiscriminatorMap


These 2 tell DQL what determines the "instance of" condition



https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/annotations-reference.html#discriminatorcolumn

Ed B. 10-02-2019 10:56 PM

Re: "Fake" orders (or how do a cart become an order ?)
 
Quote:

Originally Posted by cflsystems
That's tricky and related to Doctrine. While I am not 100% (almost 100% sure though) sure this is how XC determines which records are orders and which are not - is_order = 1 for placed orders


The Repo Order class when creating the query builder uses "placedOnly" parameter. Search the class fot it and you will see how it adds condition to select only records that are an instance of Order.

Well,
Code:

  /**
    * Create a new QueryBuilder instance that is prepopulated for this entity name
    *
    * @param string  $alias      Table alias OPTIONAL
    * @param string  $indexBy    The index for the from. OPTIONAL
    * @param boolean $placedOnly Use only orders or orders + carts OPTIONAL
    *
    * @return \XLite\Model\QueryBuilder\AQueryBuilder
    */
    public function createQueryBuilder($alias = null, $indexBy = null, $placedOnly
= true)
    {
        $result = parent::createQueryBuilder($alias, $indexBy);

        if ($placedOnly) {
            $result->andWhere($result->getMainAlias() . ' NOT INSTANCE OF XLite\Mod
el\Cart');
        }

        return $result;
    }



I didn't find the string "INSTANCE OF"... in any other class.



Are you implying that somehow because of
Code:



  * @DiscriminatorColumn  (name="is_order", type="integer", length=1)
 * @DiscriminatorMap      ({1 = "XLite\Model\Order", 0 = "XLite\Model\Cart"})

my "fake orders" become instance of XLite\Model\Cart so that get ignored
in the search? Thus if I wanted search including fake orders, I would somehow
need to use

Code:

createQueryBuilder(o,'','false);

or something like that?


Quote:



The Model Order class has these Doctrine annotations
@DiscriminatorColumn
@DiscriminatorMap


These 2 tell DQL what determines the "instance of" condition



https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/annotations-reference.html#discriminatorcolumn

cflsystems 10-03-2019 04:27 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
Yes. The DescriminatorColumn defines the column in the table and the DescriminatorMap maps its value to class.


So if you need only non-orders create new query with placeOnly equal false.


Alternatively you can just decorate the Order model class and add another field for your own use - if true it is your fake order. Then use it in a query to find your own records.

Ed B. 10-04-2019 05:38 AM

Re: "Fake" orders (or how do a cart become an order ?)
 
Quote:

Originally Posted by cflsystems
Yes. The DescriminatorColumn defines the column in the table and the DescriminatorMap maps its value to class.


So if you need only non-orders create new query with placeOnly equal false.


Alternatively you can just decorate the Order model class and add another field for your own use - if true it is your fake order. Then use it in a query to find your own records.



I think I got it. Well, if I create new query with placeOnly equal false, I will get both real and fake orders, right? Since I am removing the "where" clause.


Now my next problem is this: in the end, I would like to have ItemsList of real orders only (as there are currently) and ItemsList of fake orders only. In the future I might want to have a "mixed" list, but let's forget it for now. How can I do this?


Can I override from itemslist class the default parameter of createquerybuilder set in repo class? At a first glance, this doesn't look possible. If there is such a way, it will really save me...



Of course, I can decorate the repository class, but this would affect all itemslists concerning products. Since these itemslists don't seem to call createquerybuilder with the third argument (they don't seem to directly call createquerybuilder, so the third argument could be only set by default in the repository class), this means I will have to decorate all itemslist classes where I only want "real" orders.


I also have an extra property in the order model, but using this instead of is_order=0 gives me the same problem (well, at least I won't have to decorate the createquerybuilder function), i.e., I will have to redecorate all existing product lists not to show the fake orders.



I am tempted to create a new model "fake orders" which are in one to one to the orders that are fake, and this should solve all my problems, but I wonder if there could be a simpler way.


All times are GMT -8. The time now is 10:39 PM.

Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.