Generating Custom XML with Mass Action button

  • Posts: 171
  • Thank you received: 9
1 year 9 months ago #343066

-- HikaShop version -- : 4.6.0
-- Joomla version -- : 4.1.5
-- PHP version -- : 7.4

Hi there!

I wanna ask for some help how can I create an XML with the content in the orders.
We have an ERP system, and we got a sample XML what we can use.
Sometime we want to import the orders to the ERP with that XML.

I've successfully displayed the Mass action button, I've set it to "Run PHP code", and I've added some sample lines to check wether it is working.
But after pressing the button I got a message like:

An error has occurred.
500 Layout output not found.


Is there any way to do that with Mass Action, any sample code would be great help solving that.

Sample is like:

<?xml version="1.0" encoding="iso-8859-2" ?>
<Header>
	<Order_details>
		<Order_nr>SAMPLE001</Order_nr>
		<Date>2022.07.08 13:05:00</Date>
		<Payment_mode>Bank Transfer</Payment_mode>
		<Shipping_mode>post</Shipping_mode>
		<Order_comment></Order_comment>
		<Header_customer>
			<Customer_name>Firstname Lastname</Customer_name>
			<Customer_postalcode>1234</Customer_postalcode>
			<Customer_city>City</Customer_city>
			<Customer_street>Street Nr.</Customer_street>
			<Shipping_name>Firstname Lastname</Shipping_name>
			<Shipping_postalcode>4567</Shipping_postalcode>
			<Shipping_address1>City</Shipping_address1>
			<Shipping_address2>Street Nr.</Shipping_address2>
			<Phone>0022-123-4567</Phone>
			<Email>sample@domain.com</Email>
			<VATNr></VATNr>
		</Header_customer>
		<Items>
			<Ordered_Items>
				<Item_name>Male shoes</Item_name>
				<Item_product_code>77866684</Item_product_code>
				<Item_code>12</Item_code>
				<Item_quantity>1</Item_quantity>
				<Item_unit>pair</Item_unit>
				<Item_price_without_VAT>20000</Item_price_without_VAT>
				<VAT>20%</VAT>
				<Item_discount>0</Item_discount>
			</Ordered_Items>
		</Items>
	</Order_details>
</Header>

Thanks in advance!

PePe

Please Log in or Create an account to join the conversation.

  • Posts: 81540
  • Thank you received: 13069
  • MODERATOR
1 year 9 months ago #343070

In the textarea for your PHP code, you need to write PHP code, not HTML or XML.
So you can output XML code but you need to do that in PHP.
For example:

echo "
<?xml version="1.0" encoding="iso-8859-2" ?>
<Header>
	<Order_details>
		<Order_nr>SAMPLE001</Order_nr>
	</Order_details>
</Header>
";
Also, note that the output goes to the browser. If you just provide XML to the browser, it will add it to the page as HTML tags it doesn't know and thus you won't see anything on your browser (unless you look at the area with the HTML inspector of the development tools of your browser).
So it would be best to output it as a download file:
ob_clean();
header('Content-type: text/xml');
header('Content-Disposition: attachment;filename=myxmlfile.xml');
header('Pragma: public');
header('Cache-control: private');
header('Expires: -1');
echo "
<?xml version="1.0" encoding="iso-8859-2" ?>
<Header>
	<Order_details>
		<Order_nr>SAMPLE001</Order_nr>
	</Order_details>
</Header>
";
exit;

The following user(s) said Thank You: pepecortez

Please Log in or Create an account to join the conversation.

  • Posts: 171
  • Thank you received: 9
1 year 9 months ago #343307

Thanks, it seems it works as I needed!

For anyone else how needs:

ob_clean();

$application = JFactory::getApplication();
$orderClass = hikashop_get('class.order');
$order = $orderClass->loadFullOrder({order_id}, true, false);

if ($order->order_status != 'confirmed') {
$application->enqueueMessage(JText::_('Order is not in confirmed status, you can not export the XML! '), 'error');
return;}

$billing_address = $order->billing_address;
$shipping_address = $order->shipping_address;

header('Content-type: text/xml');
header('Content-Disposition: attachment;filename='.stripslashes($order->order_number).'.xml');
header('Pragma: public');
header('Cache-control: private');
header('Expires: -1');
echo "<?xml version=\"1.0\" encoding=\"iso-8859-2\" ?>";
echo "<Header>";
echo "<Megrendeles_adatai>";

echo "<Rendeles_szama>".$order->order_number."</Rendeles_szama>";
echo "<Datum>".hikashop_getDate($order->order_created, 'Y.m.d H:i:s')."</Datum>";
echo "<Fizetesi_mod>".$order->order_payment_method."</Fizetesi_mod>";
echo "<Szallitasi_mod>".$order->order_shipping_method."</Szallitasi_mod>";
echo "<Megjegyzes_rendeleshez>".$order->comment."</Megjegyzes_rendeleshez>";

echo "<Header_Vevo>";

echo "<Vevo_neve>".$billing_address->address_company."</Vevo_neve>";
echo "<Vevo_irsz>".$billing_address->address_post_code."</Vevo_irsz>";
echo "<Vevo_varos>".$billing_address->address_city."</Vevo_varos>";
echo "<Vevo_cim>".$billing_address->address_street." ".$billing_address->address_street2."</Vevo_cim>";

echo "<Szallitas_nev>".$shipping_address->address_lastname." ".$shipping_address->address_firstname."</Szallitas_nev>";
echo "<Szallitas_irsz>".$shipping_address->address_post_code."</Szallitas_irsz>";
echo "<Szallitas_varos>".$shipping_address->address_city."</Szallitas_varos>";
echo "<Szallitas_cim>".$shipping_address->address_street." ".$shipping_address->address_street2."</Szallitas_cim>";
echo "<Telefon>".$shipping_address->address_telephone."</Telefon>";
echo "<Email>".$order->customer->email."</Email>";

echo "<Adoszam>".$order->billing_address->address_vat."</Adoszam>";
echo "</Header_Vevo>";

echo "<Items>";
foreach($order->products as $product) {
    echo "<Megrendelt_Tetelek>";
    echo "<Termek_neve>".$product->order_product_name."</Termek_neve>"; 
    echo "<Termekkod>".$product->order_product_code."</Termekkod>";
    echo "<Cikkszam></Cikkszam>";
    echo "<Mennyiseg>".$product->order_product_quantity."</Mennyiseg>";
    echo "<Mee>"."DB"."</Mee>";
    echo "<Netto_egysegar>".$product->order_product_price."</Netto_egysegar>";
    echo "<AFA>27%</AFA>";
    echo "<Kedvezmeny_szazaleka>0</Kedvezmeny_szazaleka>";
    echo "</Megrendelt_Tetelek>";
}				
echo "</Items>";
echo "</Megrendeles_adatai>";
echo "</Header>";
exit;

The following user(s) said Thank You: nicolas

Please Log in or Create an account to join the conversation.

  • Posts: 171
  • Thank you received: 9
1 year 9 months ago #343370

"Unfortunately" I have to rewrite it a bit as our ERP can automatically import the XML from a fixed folder and fixed filename. I want to run XML generating by cron, to generate it also automatically.

To reach that I modified the Mass action to run every minute,
filter products by order status set to confirmed,
and run php code below.

1.) But I always get just the first order in the XML. Could I ask for a little help how to modify code to read all the orders to the XML?
2.) Also a problem that if I run it on Mass Actions form, it generates the XML file to /administrator folder, with cron link(/index.php?option=com_hikashop&ctrl=cron), it does not. Maybe folder permissions cause that? If yes, how should I set it to another folder?

ob_clean();

$application = JFactory::getApplication();
$orderClass = hikashop_get('class.order');
$productClass = hikashop_get('class.product');
$order = $orderClass->loadFullOrder({order_id}, true, false);

$billing_address = $order->billing_address;
$shipping_address = $order->shipping_address;

$xmlString = header('Content-type: text/xml');
$xmlString .= header('Pragma: public');
$xmlString .= header('Cache-control: private');
$xmlString .= header('Expires: -1');
$xmlString .=  "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
$xmlString .=  "<Header>";
$xmlString .=  "<Megrendeles_adatai>";

$xmlString .=  "<Rendeles_szama>".$order->order_number."</Rendeles_szama>";
$xmlString .=  "<Datum>".hikashop_getDate($order->order_created, 'Y.m.d H:i:s')."</Datum>";
$xmlString .=  "<Fizetesi_mod>".$order->order_payment_method."</Fizetesi_mod>";
$xmlString .=  "<Szallitasi_mod>".$order->order_shipping_method."</Szallitasi_mod>";
$xmlString .=  "<Megjegyzes_rendeleshez>".$order->comment."</Megjegyzes_rendeleshez>";

$xmlString .=  "<Header_Vevo>";

$xmlString .=  "<Vevo_neve>".$billing_address->address_company."</Vevo_neve>";
$xmlString .=  "<Vevo_irsz>".$billing_address->address_post_code."</Vevo_irsz>";
$xmlString .=  "<Vevo_varos>".$billing_address->address_city."</Vevo_varos>";
$xmlString .=  "<Vevo_cim>".$billing_address->address_street." ".$billing_address->address_street2."</Vevo_cim>";

$xmlString .=  "<Szallitas_nev>".$shipping_address->address_lastname." ".$shipping_address->address_firstname."</Szallitas_nev>";
$xmlString .=  "<Szallitas_irsz>".$shipping_address->address_post_code."</Szallitas_irsz>";
$xmlString .=  "<Szallitas_varos>".$shipping_address->address_city."</Szallitas_varos>";
$xmlString .=  "<Szallitas_cim>".$shipping_address->address_street." ".$shipping_address->address_street2."</Szallitas_cim>";
$xmlString .=  "<Telefon>".$shipping_address->address_telephone."</Telefon>";
$xmlString .=  "<Email>".$order->customer->email."</Email>";

$xmlString .=  "<Adoszam>".$order->billing_address->address_vat."</Adoszam>";
$xmlString .=  "</Header_Vevo>";

$xmlString .=  "<Items>";
foreach($order->products as $product) {
$productData = $productClass->get($product->product_id);
    $xmlString .= "<Megrendelt_Tetelek>";
    $xmlString .= "<Termek_neve>".$product->order_product_name."</Termek_neve>"; 
    $xmlString .= "<Termekkod>".$product->order_product_code."</Termekkod>";
    $xmlString .= "<Cikkszam></Cikkszam>";
    $xmlString .= "<Mennyiseg>".$product->order_product_quantity."</Mennyiseg>";
    $xmlString .= "<Mee>".$productData->mennyisegiegyseg."</Mee>";
    $xmlString .= "<Netto_egysegar>".$product->order_product_price."</Netto_egysegar>";
    $xmlString .= "<AFA>27%</AFA>";
    $xmlString .= "<Kedvezmeny_szazaleka>0</Kedvezmeny_szazaleka>";
    $xmlString .= "</Megrendelt_Tetelek>";
}				
$xmlString .= "</Items>";
$xmlString .= "</Megrendeles_adatai>";
$xmlString .= "</Header>";

$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xmlString);

$dom->save('orders.xml');

exit;

Last edit: 1 year 9 months ago by pepecortez.

Please Log in or Create an account to join the conversation.

  • Posts: 81540
  • Thank you received: 13069
  • MODERATOR
1 year 9 months ago #343376

Hi,

1. The action will run once for each order filtered by the filters of your mass action.
So here, there is not much point in using a mass action for what you want to do.
I would rather recommend you develop a plugin ( www.hikashop.com/support/documentation/6...r-documentation.html ) implementing the onHikashopCronTrigger (
www.hikashop.com/support/documentation/6...nHikashopCronTrigger ) event. In it, you would first run a MySQL query to load the confirmed orders, and then you would generate the XML file.

2. That's because of your line: $dom->save('orders.xml');
You only provide the filename. But in the backend, the current folder in /administrator/ while on the frontend (where the cron runs) the current folder is /.
The solution is to provide the full folder like this: $dom->save(HIKASHOP_ROOT.'orders.xml');
That way it will always save it on the root folder of the website.

The following user(s) said Thank You: pepecortez

Please Log in or Create an account to join the conversation.

  • Posts: 171
  • Thank you received: 9
1 year 9 months ago #343469

Both of your replies were really helpful.
1.) I've used your google products plugin - of course I've elminated a few params from it - as a prefect example I can rewrite to fit my needs. Now cron does the job - generates XML with all the needed data, the ERP is checking and reads in automatically. Thanks a lot.

Here's the main part, the generateXML function, and I also attached a .htaccess file to only be readable by the ERP's IP:

	function generateXML() {
		if(!hikashop_level(1))
			return '';

		$app = JFactory::getApplication();
		$db = JFactory::getDBO();
		$pluginsClass = hikashop_get('class.plugins');
		$plugin = $pluginsClass->getByName('hikashop','google_products');
	
		$query = 'SELECT * FROM '.hikashop_table('order').' WHERE order_status=\'confirmed\'';
		
		$db->setQuery($query);
		$orders = $db->loadObjectList();

		if(empty($orders)){
			return true;
		}

		$ids = array();
		foreach($orders as $key => $row){
			$ids[] = (int)$row->order_id;
			$products[$key]->alias = JFilterOutput::stringURLSafe($row->order_number);
		}
		
		$conf = JFactory::getConfig();
		if(!HIKASHOP_J30) {
			$siteName = $conf->getValue('config.sitename');
			$siteDesc = $conf->getValue('config.MetaDesc');
		} else {
			$siteName = $conf->get('sitename');
			$siteDesc = $conf->get('MetaDesc');
		}
		
		$siteAddress = JURI::base();
		$siteAddress = str_replace('administrator/','',$siteAddress);
		$xml = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
		
		$productClass = hikashop_get('class.product');
		$volumeHelper = hikashop_get('helper.volume');
		$weightHelper = hikashop_get('helper.weight');

		foreach($orders as $order) {

			$orderClass = hikashop_get('class.order');
			$order = $orderClass->loadFullOrder($order->order_id, true, false);

			$billing_address = $order->billing_address;
			$shipping_address = $order->shipping_address;

			
			$xml .=  "<Header>";
			$xml .=  "<Megrendeles_adatai>";

			$xml .=  "<Rendeles_szama>".$order->order_number."</Rendeles_szama>";
			$xml .=  "<Datum>".hikashop_getDate($order->order_created, 'Y.m.d H:i:s')."</Datum>";
			$xml .=  "<Fizetesi_mod>".$order->order_payment_method."</Fizetesi_mod>";
			$xml .=  "<Szallitasi_mod>".$order->order_shipping_method."</Szallitasi_mod>";
			$xml .=  "<Megjegyzes_rendeleshez>".$order->comment."</Megjegyzes_rendeleshez>";

			$xml .=  "<Header_Vevo>";

			$xml .=  "<Vevo_neve>".$billing_address->address_company."</Vevo_neve>";
			$xml .=  "<Vevo_irsz>".$billing_address->address_post_code."</Vevo_irsz>";
			$xml .=  "<Vevo_varos>".$billing_address->address_city."</Vevo_varos>";
			$xml .=  "<Vevo_cim>".$billing_address->address_street." ".$billing_address->address_street2."</Vevo_cim>";

			$xml .=  "<Szallitas_nev>".$shipping_address->address_lastname." ".$shipping_address->address_firstname."</Szallitas_nev>";
			$xml .=  "<Szallitas_irsz>".$shipping_address->address_post_code."</Szallitas_irsz>";
			$xml .=  "<Szallitas_varos>".$shipping_address->address_city."</Szallitas_varos>";
			$xml .=  "<Szallitas_cim>".$shipping_address->address_street." ".$shipping_address->address_street2."</Szallitas_cim>";
			$xml .=  "<Telefon>".$shipping_address->address_telephone."</Telefon>";
			$xml .=  "<Email>".$order->customer->email."</Email>";

			$xml.=  "<Adoszam>".$order->billing_address->address_vat."</Adoszam>";
			$xml .=  "</Header_Vevo>";

			$xml .=  "<Items>";
			foreach($order->products as $product) {
			$productData = $productClass->get($product->product_id);
				$xml .= "<Megrendelt_Tetelek>";
				$xml .= "<Termek_neve>".$product->order_product_name."</Termek_neve>"; 
				$xml .= "<Termekkod>".$product->order_product_code."</Termekkod>";
				$xml .= "<Cikkszam></Cikkszam>";
				$xml .= "<Mennyiseg>".$product->order_product_quantity."</Mennyiseg>";
				$xml .= "<Mee>".$productData->mennyisegiegyseg."</Mee>";
				$xml .= "<Netto_egysegar>".$product->order_product_price."</Netto_egysegar>";
				$xml .= "<AFA>27%</AFA>";
				$xml .= "<Kedvezmeny_szazaleka>0</Kedvezmeny_szazaleka>";
				$xml .= "</Megrendelt_Tetelek>";
			}				
			$xml .= "</Items>";
			$xml .= "</Megrendeles_adatai>";
			$xml .= "</Header>";
		}
		return $xml;
	}

}

2.) $dom->save(HIKASHOP_ROOT.'orders.xml'); -> was also useful, works as u described.


nicolas wrote: Hi,

1. The action will run once for each order filtered by the filters of your mass action.
So here, there is not much point in using a mass action for what you want to do.
I would rather recommend you develop a plugin ( www.hikashop.com/support/documentation/6...r-documentation.html ) implementing the onHikashopCronTrigger (
www.hikashop.com/support/documentation/6...nHikashopCronTrigger ) event. In it, you would first run a MySQL query to load the confirmed orders, and then you would generate the XML file.

2. That's because of your line: $dom->save('orders.xml');
You only provide the filename. But in the backend, the current folder in /administrator/ while on the frontend (where the cron runs) the current folder is /.
The solution is to provide the full folder like this: $dom->save(HIKASHOP_ROOT.'orders.xml');
That way it will always save it on the root folder of the website.

The following user(s) said Thank You: nicolas

Please Log in or Create an account to join the conversation.

Time to create page: 0.067 seconds
Powered by Kunena Forum