Passed
Push — master ( 694c78...f1dcbc )
by Aimeos
06:27 queued 02:01
created

Standard::getName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2014
6
 * @copyright Aimeos (aimeos.org), 2015-2021
7
 * @package Controller
8
 * @subpackage Order
9
 */
10
11
12
namespace Aimeos\Controller\Jobs\Order\Email\Delivery;
13
14
use \Aimeos\MW\Logger\Base as Log;
15
16
17
/**
18
 * Order delivery e-mail job controller.
19
 *
20
 * @package Controller
21
 * @subpackage Order
22
 */
23
class Standard
24
	extends \Aimeos\Controller\Jobs\Base
25
	implements \Aimeos\Controller\Jobs\Iface
26
{
27
	/**
28
	 * Returns the localized name of the job.
29
	 *
30
	 * @return string Name of the job
31
	 */
32
	public function getName() : string
33
	{
34
		return $this->getContext()->translate( 'controller/jobs', 'Order delivery related e-mails' );
35
	}
36
37
38
	/**
39
	 * Returns the localized description of the job.
40
	 *
41
	 * @return string Description of the job
42
	 */
43
	public function getDescription() : string
44
	{
45
		return $this->getContext()->translate( 'controller/jobs', 'Sends order delivery status update e-mails' );
46
	}
47
48
49
	/**
50
	 * Executes the job.
51
	 *
52
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
53
	 */
54
	public function run()
55
	{
56
		$context = $this->getContext();
57
		$config = $context->getConfig();
58
59
		$client = \Aimeos\Client\Html\Email\Delivery\Factory::create( $context );
60
61
		$orderManager = \Aimeos\MShop::create( $context, 'order' );
62
63
		/** controller/jobs/order/email/delivery/limit-days
64
		 * Only send delivery e-mails of orders that were created in the past within the configured number of days
65
		 *
66
		 * The delivery e-mails are normally send immediately after the delivery
67
		 * status has changed. This option prevents e-mails for old order from
68
		 * being send in case anything went wrong or an update failed to avoid
69
		 * confusion of customers.
70
		 *
71
		 * @param integer Number of days
72
		 * @since 2014.03
73
		 * @category User
74
		 * @category Developer
75
		 * @see controller/jobs/order/email/delivery/status
76
		 * @see controller/jobs/order/email/payment/limit-days
77
		 * @see controller/jobs/service/delivery/process/limit-days
78
		 */
79
		$limit = $config->get( 'controller/jobs/order/email/delivery/limit-days', 90 );
80
		$limitDate = date( 'Y-m-d H:i:s', time() - $limit * 86400 );
81
82
		$default = array(
83
			\Aimeos\MShop\Order\Item\Base::STAT_PROGRESS,
84
			\Aimeos\MShop\Order\Item\Base::STAT_DISPATCHED,
85
			\Aimeos\MShop\Order\Item\Base::STAT_REFUSED,
86
			\Aimeos\MShop\Order\Item\Base::STAT_RETURNED,
87
		);
88
89
		/** controller/jobs/order/email/delivery/status
90
		 * Only send order delivery notification e-mails for these delivery status values
91
		 *
92
		 * Notification e-mail about delivery status changes can be sent for these
93
		 * status values:
94
		 *
95
		 * * 0: deleted
96
		 * * 1: pending
97
		 * * 2: progress
98
		 * * 3: dispatched
99
		 * * 4: delivered
100
		 * * 5: lost
101
		 * * 6: refused
102
		 * * 7: returned
103
		 *
104
		 * User-defined status values are possible but should be in the private
105
		 * block of values between 30000 and 32767.
106
		 *
107
		 * @param integer Delivery status constant
108
		 * @since 2014.03
109
		 * @category User
110
		 * @category Developer
111
		 * @see controller/jobs/order/email/payment/status
112
		 * @see controller/jobs/order/email/delivery/limit-days
113
		 */
114
		foreach( (array) $config->get( 'controller/jobs/order/email/delivery/status', $default ) as $status )
115
		{
116
			$start = 0;
117
			$orderSearch = $orderManager->filter();
118
119
			$param = array( \Aimeos\MShop\Order\Item\Status\Base::EMAIL_DELIVERY, (string) $status );
120
			$orderFunc = $orderSearch->make( 'order:status', $param );
121
122
			$expr = array(
123
				$orderSearch->compare( '>=', 'order.mtime', $limitDate ),
124
				$orderSearch->compare( '==', 'order.statusdelivery', $status ),
125
				$orderSearch->compare( '==', $orderFunc, 0 ),
126
			);
127
			$orderSearch->setConditions( $orderSearch->and( $expr ) );
128
129
			do
130
			{
131
				$orderSearch->slice( $start );
132
				$items = $orderManager->search( $orderSearch );
133
134
				$this->process( $client, $items, $status );
135
136
				$count = count( $items );
137
				$start += $count;
138
			}
139
			while( $count >= $orderSearch->getLimit() );
140
		}
141
	}
142
143
144
	/**
145
	 * Adds the status of the delivered e-mail for the given order ID
146
	 *
147
	 * @param string $orderId Unique order ID
148
	 * @param int $value Status value
149
	 */
150
	protected function addOrderStatus( string $orderId, int $value )
151
	{
152
		$orderStatusManager = \Aimeos\MShop::create( $this->getContext(), 'order/status' );
153
154
		$statusItem = $orderStatusManager->create();
155
		$statusItem->setParentId( $orderId );
156
		$statusItem->setType( \Aimeos\MShop\Order\Item\Status\Base::EMAIL_DELIVERY );
157
		$statusItem->setValue( $value );
158
159
		$orderStatusManager->save( $statusItem );
160
	}
161
162
163
	/**
164
	 * Returns the delivery address item of the order
165
	 *
166
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem Order including address items
167
	 * @return \Aimeos\MShop\Order\Item\Base\Address\Iface Delivery or payment address item
168
	 * @throws \Aimeos\Controller\Jobs\Exception If no address item is available
169
	 */
170
	protected function getAddressItem( \Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem ) : \Aimeos\MShop\Order\Item\Base\Address\Iface
171
	{
172
		$type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_DELIVERY;
173
		if( ( $addr = current( $orderBaseItem->getAddress( $type ) ) ) !== false && $addr->getEmail() !== '' ) {
174
			return $addr;
175
		}
176
177
		$type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_PAYMENT;
178
		if( ( $addr = current( $orderBaseItem->getAddress( $type ) ) ) !== false ) {
179
			return $addr;
180
		}
181
182
		$msg = sprintf( 'No address found in order base with ID "%1$s"', $orderBaseItem->getId() );
183
		throw new \Aimeos\Controller\Jobs\Exception( $msg );
184
	}
185
186
187
	/**
188
	 * Returns an initialized view object
189
	 *
190
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context item
191
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem Complete order including addresses, products, services
192
	 * @param string|null $langId ISO language code, maybe country specific
193
	 * @return \Aimeos\MW\View\Iface Initialized view object
194
	 */
195
	protected function view( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem, string $langId = null ) : \Aimeos\MW\View\Iface
196
	{
197
		$view = $context->view();
198
199
		$params = [
200
			'locale' => $langId,
201
			'site' => $orderBaseItem->getSiteCode(),
202
			'currency' => $orderBaseItem->getLocale()->getCurrencyId()
203
		];
204
205
		$helper = new \Aimeos\MW\View\Helper\Param\Standard( $view, $params );
206
		$view->addHelper( 'param', $helper );
207
208
		$helper = new \Aimeos\MW\View\Helper\Number\Locale( $view, $langId );
209
		$view->addHelper( 'number', $helper );
210
211
		$helper = new \Aimeos\MW\View\Helper\Config\Standard( $view, $context->getConfig() );
212
		$view->addHelper( 'config', $helper );
213
214
		$helper = new \Aimeos\MW\View\Helper\Mail\Standard( $view, $context->getMail()->createMessage() );
215
		$view->addHelper( 'mail', $helper );
216
217
		$helper = new \Aimeos\MW\View\Helper\Translate\Standard( $view, $context->getI18n( $langId ) );
218
		$view->addHelper( 'translate', $helper );
219
220
		return $view;
221
	}
222
223
224
	/**
225
	 * Sends the delivery e-mail for the given orders
226
	 *
227
	 * @param \Aimeos\Client\Html\Iface $client HTML client object for rendering the delivery e-mails
228
	 * @param \Aimeos\Map $items List of order items implementing \Aimeos\MShop\Order\Item\Iface with their IDs as keys
229
	 * @param int $status Delivery status value
230
	 */
231
	protected function process( \Aimeos\Client\Html\Iface $client, \Aimeos\Map $items, int $status )
232
	{
233
		$context = $this->getContext();
234
		$orderBaseManager = \Aimeos\MShop::create( $context, 'order/base' );
235
236
		foreach( $items as $id => $item )
237
		{
238
			try
239
			{
240
				$orderBaseItem = $orderBaseManager->load( $item->getBaseId() );
241
				$addr = $this->getAddressItem( $orderBaseItem );
242
243
				if( $addr->getEmail() )
244
				{
245
					$this->processItem( $client, $item, $orderBaseItem, $addr );
246
247
					$str = sprintf( 'Sent order delivery e-mail for status "%1$s" to "%2$s"', $status, $addr->getEmail() );
248
					$context->getLogger()->log( $str, Log::INFO, 'email/order/delivery' );
249
				}
250
251
				$this->addOrderStatus( $id, $status );
252
			}
253
			catch( \Exception $e )
254
			{
255
				$str = 'Error while trying to send delivery e-mail for order ID "%1$s" and status "%2$s": %3$s';
256
				$msg = sprintf( $str, $item->getId(), $item->getStatusDelivery(), $e->getMessage() );
257
				$context->getLogger()->log( $msg . PHP_EOL . $e->getTraceAsString(), Log::ERR, 'email/order/payment' );
258
			}
259
		}
260
	}
261
262
263
	/**
264
	 * Sends the delivery related e-mail for a single order
265
	 *
266
	 * @param \Aimeos\Client\Html\Iface $client HTML client object for rendering the delivery e-mails
267
	 * @param \Aimeos\MShop\Order\Item\Iface $orderItem Order item the delivery related e-mail should be sent for
268
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem Complete order including addresses, products, services
269
	 * @param \Aimeos\MShop\Order\Item\Base\Address\Iface $addrItem Address item to send the e-mail to
270
	 */
271
	protected function processItem( \Aimeos\Client\Html\Iface $client, \Aimeos\MShop\Order\Item\Iface $orderItem,
272
		\Aimeos\MShop\Order\Item\Base\Iface $orderBaseItem, \Aimeos\MShop\Order\Item\Base\Address\Iface $addrItem )
273
	{
274
		$context = $this->getContext();
275
		$langId = ( $addrItem->getLanguageId() ?: $orderBaseItem->getLocale()->getLanguageId() );
276
277
		$view = $this->view( $context, $orderBaseItem, $langId );
278
		$view->extAddressItem = $addrItem;
279
		$view->extOrderBaseItem = $orderBaseItem;
280
		$view->extOrderItem = $orderItem;
281
282
		$client->setView( $view );
283
		$client->header();
284
		$client->body();
285
286
		$context->getMail()->send( $view->mail() );
287
	}
288
}
289