Jump to content
thirty bees forum
  • 0

Solved: Do Something when Valid Order with Payment is placed


Question

Posted (edited)

Objective:  Hook and perform an action when a valid order is place with payment.  This should be done before any emails are sent.

I have a Thirty Bees shop that started as Prestashop in 2012, migrated to Thirty Bees (now using version 1.6.0) and has been used successfully for our club.  It includes modifications and custom fields that are stored in the ps_customer table. I use overrides and custom templates so that membership cards with a unique membership number are included in the pdf invoice generated. This pdf is sent with the order email.  For existing members, this works great.  For new members I need to manually assign the proper member number, then send an email with the paid invoice.  I would like to automate the member number assignment before the order confirmation email is sent so it picks up the member number for the email.

I'm thinking that an override to OrderConfirmationController.php in public function displayPaymentReturn() is the best place to do this.  Is that correct or is there a better place?

Proposed Approach: Below outlines the action to be performed

  • Detect when a paid order is placed and get the id_customer as $id_customer
  • If custom field 'member' in ps_customer table is not empty, exit and continue the normal process
  • If the order does not include the product reference "MemberDues" or "AssocMembr", exit and continue the normal process
  • If the order includes the product reference "MemberDues", $sql = 'SELECT MAX(member) from ps_customer WHERE member BETWEEN '1' AND '4999'" 
  • If the order includes the product reference "AssocMembr", $sql = 'SELECT MAX(member) from ps_customer WHERE member BETWEEN '5000' AND '7999' "; 
  • execute the sql query to obtain the largest member number, and add 1 to the result for the next member number to assign as $new_number
  • execute a sql query to update the member number for the customer, $sql = "UPDATE ps_customer SET member = '$new_number'  WHERE id_customer = '$id_customer' ";
  • continue the normal process

Please comment if there is a better way to accomplish this before I march off and do the code.

Edited by Rhapsody
mark as solved

10 answers to this question

Recommended Posts

  • 0
Posted

I would probably create a small module instead of doing overrides.

If I understand your question than you only need to modify DB table of customer with extra data that later order confirmation email with pdf will do the job based on that value.

If thats the case I will create a module with a single hook of `hookActionValidateOrder` which provide in the $params argument everything you need to run your logic.

$params will include: order, cart, customer, currency and orderStatus.

of course you need to place it first in the modules -> positions -> actionValidateOrder.

all payment module on success payment calls `PaymentModule::validateOrder()` which trigger modules `hookActionValidateOrder` before the order_conf email is sent.

  • Like 1
  • 0
Posted
7 hours ago, yaniv14 said:

I would probably create a small module instead of doing overrides.

If I understand your question than you only need to modify DB table of customer with extra data that later order confirmation email with pdf will do the job based on that value.

If thats the case I will create a module with a single hook of `hookActionValidateOrder` which provide in the $params argument everything you need to run your logic.

$params will include: order, cart, customer, currency and orderStatus.

of course you need to place it first in the modules -> positions -> actionValidateOrder.

all payment module on success payment calls `PaymentModule::validateOrder()` which trigger modules `hookActionValidateOrder` before the order_conf email is sent.

@yaniv14 - Thanks for the suggestion.  I used your advice and created a module.  It works (kind of).  I pasted the code below.  The member number is created and saved in the ps_customer table member field.  What isn't working is when the pdf invoice is emailed with the order confirmation, the new member number when it is assigned on that order isn't passed.  If it is a membership renewal (e.g. member number already exists) the member number is passed and the pdf is correct.  If I go to the Order History & Details and open the PDF, the newly assigned member number is there.

Any ideas on what I'm missing?

 

<?php
// memberautonumber.php auto assigns member numbers when new membership purchased
class MemberAutoNumber extends Module
{
    public function __construct()
    {
        $this->name = 'memberautonumber';
        $this->tab = 'administration'; // Optional: Tab for the module in the back office
        $this->version = '1.0.0';
        $this->author = 'Bill Kneller';

        parent::__construct();

        $this->displayName = $this->l('Member Auto Number'); // Display name in back office
        $this->description = $this->l('CHNYC Member numbers are automatically assigned when new membership is purchased'); // Description in back office
    }

    public function install()
    {
        // Installation logic (e.g., database creation, configuration)
        return parent::install() &&
               $this->registerHook('hookActionValidateOrder') && $this->registerHook('actionValidateOrder'); // Register a hook
    }

    public function uninstall()
    {
        // Uninstallation logic (e.g., database deletion, configuration removal)
        return parent::uninstall() &&
               $this->unregisterHook('hookActionValidateOrder') && $this->unregisterHook('actionValidateOrder'); // Unregister the hook
    }

    public function hookActionValidateOrder($params)
    {
        // Getting differents vars
        // $params will include: order, cart, customer, currency and orderStatus.
        $context = Context::getContext();
        $idLang = (int) $context->language->id;
        $idShop = (int) $context->shop->id;
        $currency = $params['currency'];
        $order = $params['order'];
        $customer = $params['customer'];
        $cart = $params['cart'];
        $orderState = $params['orderStatus'];

	            $id_customer = (int)$this->context->cookie->id_customer;
	            $customer = new Customer($id_customer);
				$member = $customer->member;
				$products = $order->getProducts();
            	//loop and check product reference for membership
				if (empty($member)) foreach ($products as $key => $product) {
					$condition = null;
					if (str_contains($product['product_name'] , 'CHNYC Annual Membership')) $condition = "WHERE member BETWEEN '1' AND '4999'";
					if (str_contains($product['product_name'] , 'CHNYC Associate Membership')) $condition = "WHERE member BETWEEN '5000' AND '7999'";
					if (!empty($condition)) {
						$sql = 'SELECT MAX(member) from ps_customer ' . $condition;
						$member = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); //last used member number
						$member = $member[0]["MAX(member)"];
						++$member; // this is the next member number
						$sql = "UPDATE ps_customer SET member = '$member'  WHERE id_customer = '$id_customer' ";
						$status = Db::getInstance(_PS_USE_SQL_SLAVE_)->execute($sql); //updates member number
					} // if (!empty($condition))
				} // if (empty($member)) foreach ($products as $key => $product)
        return; 
    }
}

 

  • 0
Posted

@yaniv14 I use the built in templates modified, and it works for orders where the member number was previously assigned..  In my themes/pdf folder I have added fields to display:

 Membership # {$customer->member} <br>

I have an override placed in \shop\override\classes\pdf\HTMLTemplateInvoice.php that gets the customer table fields (including member) with the following code:

<?php
/**
 * HTMLTemplateInvoice.php
 *
 * Override for 30 Bees 1.6.0 HTMLTemplateInvoice.php to get order messages so they can be displayed in pdf invoice
 * Adds custom variables for membership card based on Commodore assigned in Customer table (Crew Manager Commented Out)
 * Adds scratch sheet information variables (Crew Manager Commented Out)
 * Adds address fields to format pdf
 * Adds custom variables in ps_configuration table
 * PS_COMMODORE = 'commodore', PS_ASSOCIATE_MEMBER_VOUCHER = 'associate_member_voucher'
 * PS_REGULAR_MEMBER_VOUCHER = regular_member_voucher'
 * PS_VOUCHER_TEXT = 'voucher_text'
 * PS_VOUCHER_ENABLE = 'voucher_enable'
 *
 */

class HTMLTemplateInvoice extends HTMLTemplateInvoiceCore
{
    /**
     * Returns the template's HTML content
     *
     * @return string HTML content
     *
     * @throws PrestaShopDatabaseException
     * @throws PrestaShopException
     * @throws SmartyException
     */
    public function getContent()
    {
/****************  CHNYC adds **********************/
		$country = new Country((int)$this->order->id_address_invoice);
		$invoice_address = new Address((int)$this->order->id_address_invoice);
		$formatted_invoice_address = AddressFormat::generateAddress($invoice_address, array(), '<br />', ' ');
		$formatted_delivery_address = '';

		if ($this->order->id_address_delivery != $this->order->id_address_invoice)
		{
			$delivery_address = new Address((int)$this->order->id_address_delivery);
			$formatted_delivery_address = AddressFormat::generateAddress($delivery_address, array(), '<br />', ' ');
		}

		$customer = new Customer((int)$this->order->id_customer);
/*******************  CHNYC Adds above  *********************************/


/************** Get Address fields for PDF  ***************************/

        $invoice = new Address((int) $this->order->id_address_invoice);
        $delivery = new Address((int) $this->order->id_address_delivery);
        $delivery_state_iso = $delivery->id_state ? new State((int)$delivery->id_state) : false;
        $invoice_state_iso = $invoice->id_state ? new State((int)$invoice->id_state) : false;
        $delivery_state = $delivery->id_state ? new State((int)$delivery->id_state) : false;
        $invoice_state = $invoice->id_state ? new State((int)$invoice->id_state) : false;

        $sqlDelivery = "SELECT a.`company`, a.`other` FROM `" ._DB_PREFIX_. "address` a
            WHERE a.id_address = " .(int)$this->order->id_address_delivery;

        $delivery_fields = Db::getInstance()->getRow($sqlDelivery); // delivery address fields

        $sqlInvoice = "SELECT a.`company`, a.`other` FROM `" ._DB_PREFIX_. "address` a
            WHERE a.id_address = " .(int)$this->order->id_address_invoice;

        $invoice_fields = Db::getInstance()->getRow($sqlInvoice); // invoice address fields
//        var_dump($delivery_fields);

/************** End Get Address fields for PDF  *********************/

        $orderDetails = $this->order_invoice->getProducts();

        $hasDiscount = false;
        foreach ($orderDetails as $id => &$orderDetail) {
            // Find out if column 'price before discount' is required
            if ($orderDetail['reduction_amount_tax_excl'] > 0) {
                $hasDiscount = true;
                $orderDetail['unit_price_tax_excl_before_specific_price'] = $orderDetail['unit_price_tax_excl_including_ecotax'] + $orderDetail['reduction_amount_tax_excl'];
            } elseif ($orderDetail['reduction_percent'] > 0) {
                $hasDiscount = true;
                $orderDetail['unit_price_tax_excl_before_specific_price'] = (100 * $orderDetail['unit_price_tax_excl_including_ecotax']) / (100 - $orderDetail['reduction_percent']);
            }

		}

         $this->smarty->assign(array(

/**** CHNYC extra fields ********/
			'voucher_text' => Configuration::get('PS_VOUCHER_TEXT'),
			'commodore' => Configuration::get('PS_COMMODORE'),
			'associate_member_voucher' => Configuration::get('PS_ASSOCIATE_MEMBER_VOUCHER'),
			'regular_member_voucher' => Configuration::get('PS_REGULAR_MEMBER_VOUCHER'),		
			'voucher_enable' => Configuration::get('PS_VOUCHER_ENABLE'),
			'customer' => $customer,
/****** end CHNYC Extra Fields *****/
			'order' => $this->order,
			'order_details' => $this->order_invoice->getProducts(),
			'delivery_company' 			 => $delivery_fields['company'],
			'delivery_firstname'		 => $delivery->firstname,
			'delivery_lastname'			 => $delivery->lastname,
			'delivery_address1'			 => $delivery->address1,
			'delivery_address2'			 => $delivery->address2,
			'delivery_city'				 => $delivery->city,
			'delivery_postal_code'		 => $delivery->postcode,
			'delivery_country'			 => $delivery->country,
			'delivery_state_iso'		 => $delivery->id_state ? $delivery_state->iso_code : '',
			'delivery_state'			 => $delivery->id_state ? $delivery_state->name : '',
			'delivery_phone'			 => $delivery->phone,
			'delivery_phone_mobile'		 => $delivery->phone_mobile,
			'delivery_other'			 => $delivery_fields['other'],
			'invoice_company'			 => $invoice_fields['company'],
			'invoice_firstname'			 => $invoice->firstname,

			'invoice_lastname'			 => $invoice->lastname,
			'invoice_address2'			 => $invoice->address2,
			'invoice_address1'			 => $invoice->address1,
			'invoice_city'				 => $invoice->city,
			'invoice_postal_code'		 => $invoice->postcode,
			'invoice_country'			 => $invoice->country,
			'invoice_state_iso'				 => $invoice->id_state ? $invoice_state->iso_code : '',
			'invoice_state'				 => $invoice->id_state ? $invoice_state->name : '',
			'invoice_phone'				 => $invoice->phone,
			'invoice_phone_mobile'		 => $invoice->phone_mobile,
			'invoice_other'				 => $invoice_fields['other'],

            'messages' =>  CustomerMessage::getMessagesByOrderId((int)($this->order->id), false),

         ));

            return parent::getContent();

   }

}


 

  • 0
Posted (edited)

Thinking about this... might it be possible that the new hook I created is getting called after the order confirmation email that generates & attaches the pdf?  That means the member field in the ps_customer table has not been updated so when the $customer object is passed, the member number is still blank.  If so, how do I prioritize the new hook to have a higher priority and perform the action first?

Edited by Rhapsody
  • 0
Posted

PDF Invoice attachment to "order_conf" email is generated in the PaymentModule class.
The data for generated PDF Invoice is retrieved using the $order->getInvoicesCollection() method
i.e.:
public function getInvoicesCollection()
{
    $orderInvoices = new PrestaShopCollection('OrderInvoice');
    $orderInvoices->where('id_order', '=', $this->id);
    return $orderInvoices;
}

And in PrestaShopCollection('OrderInvoice') there is definitely no custom data added by you to the customer's account.
In your module, you can add your own custom data via the displayPDFInvoice hook.

 

  • 0
Posted (edited)

@Yabber That didn't work for me.  I cam up with a work around so there is a note on the order confirmation email with a link to the order history so they may download the PDF that is properly set with the new member number. Existing members on renewal can use the PDF invoice attached to the email.  

I consider this solved and thank all for the help. I used the custom module approach.

Edited by Rhapsody
  • 0
Posted

Can you try instead of passing $customer variable to smarty to pass the membership, and use that variable instead.

/**** CHNYC extra fields ********/
			'voucher_text' => Configuration::get('PS_VOUCHER_TEXT'),
			'commodore' => Configuration::get('PS_COMMODORE'),
			'associate_member_voucher' => Configuration::get('PS_ASSOCIATE_MEMBER_VOUCHER'),
			'regular_member_voucher' => Configuration::get('PS_REGULAR_MEMBER_VOUCHER'),		
			'voucher_enable' => Configuration::get('PS_VOUCHER_ENABLE'),
			'customer' => $customer,
                        'customer_membership' => $customer->member,
/****** end CHNYC Extra Fields *****/
  • 0
Posted

This should work properly only via the module:

    public function hookActionPDFInvoiceRender(array $params)
    {
        if (isset($params['order_invoice_list'])) {
            foreach ($params['order_invoice_list'] as $orderInvoice) {
                if (Validate::isLoadedObject($orderInvoice)) {
                    if ($member = $this->yourValidateCustomerMethod((int) $orderInvoice->id_order)) {
                        $this->context->smarty->assign(
                            [
                                'member' => $member
                            ]
                        );
                    }
                }
            }
        }
    }

And in PDF template:

{if isset($member) && $member}
    <p>{l s='Member number:' pdf='true'} {$member}</p>
{/if}

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...