Passed
Push — master ( d2fcbc...0a49bb )
by Aimeos
02:57
created

Standard::domains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 22
rs 10
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-2022
7
 * @package Controller
8
 * @subpackage Jobs
9
 */
10
11
12
namespace Aimeos\Controller\Jobs\Order\Service\Delivery;
13
14
15
/**
16
 * Sends paid orders to the ERP system or logistic partner.
17
 *
18
 * @package Controller
19
 * @subpackage Jobs
20
 */
21
class Standard
22
	extends \Aimeos\Controller\Jobs\Base
23
	implements \Aimeos\Controller\Jobs\Iface
24
{
25
	/** controller/jobs/order/service/delivery/name
26
	 * Class name of the used order service delivery scheduler controller implementation
27
	 *
28
	 * Each default job controller can be replace by an alternative imlementation.
29
	 * To use this implementation, you have to set the last part of the class
30
	 * name as configuration value so the controller factory knows which class it
31
	 * has to instantiate.
32
	 *
33
	 * For example, if the name of the default class is
34
	 *
35
	 *  \Aimeos\Controller\Jobs\Order\Service\Delivery\Standard
36
	 *
37
	 * and you want to replace it with your own version named
38
	 *
39
	 *  \Aimeos\Controller\Jobs\Order\Service\Delivery\Mydelivery
40
	 *
41
	 * then you have to set the this configuration option:
42
	 *
43
	 *  controller/jobs/order/service/delivery/name = Mydelivery
44
	 *
45
	 * The value is the last part of your own class name and it's case sensitive,
46
	 * so take care that the configuration value is exactly named like the last
47
	 * part of the class name.
48
	 *
49
	 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
50
	 * characters are possible! You should always start the last part of the class
51
	 * name with an upper case character and continue only with lower case characters
52
	 * or numbers. Avoid chamel case names like "MyDelivery"!
53
	 *
54
	 * @param string Last part of the class name
55
	 * @since 2014.03
56
	 */
57
58
	/** controller/jobs/order/service/delivery/decorators/excludes
59
	 * Excludes decorators added by the "common" option from the order service delivery controllers
60
	 *
61
	 * Decorators extend the functionality of a class by adding new aspects
62
	 * (e.g. log what is currently done), executing the methods of the underlying
63
	 * class only in certain conditions (e.g. only for logged in users) or
64
	 * modify what is returned to the caller.
65
	 *
66
	 * This option allows you to remove a decorator added via
67
	 * "controller/jobs/common/decorators/default" before they are wrapped
68
	 * around the job controller.
69
	 *
70
	 *  controller/jobs/order/service/delivery/decorators/excludes = array( 'decorator1' )
71
	 *
72
	 * This would remove the decorator named "decorator1" from the list of
73
	 * common decorators ("\Aimeos\Controller\Jobs\Common\Decorator\*") added via
74
	 * "controller/jobs/common/decorators/default" to this job controller.
75
	 *
76
	 * @param array List of decorator names
77
	 * @since 2015.09
78
	 * @see controller/jobs/common/decorators/default
79
	 * @see controller/jobs/order/service/delivery/decorators/global
80
	 * @see controller/jobs/order/service/delivery/decorators/local
81
	 */
82
83
	/** controller/jobs/order/service/delivery/decorators/global
84
	 * Adds a list of globally available decorators only to the order service delivery controllers
85
	 *
86
	 * Decorators extend the functionality of a class by adding new aspects
87
	 * (e.g. log what is currently done), executing the methods of the underlying
88
	 * class only in certain conditions (e.g. only for logged in users) or
89
	 * modify what is returned to the caller.
90
	 *
91
	 * This option allows you to wrap global decorators
92
	 * ("\Aimeos\Controller\Jobs\Common\Decorator\*") around the job controller.
93
	 *
94
	 *  controller/jobs/order/service/delivery/decorators/global = array( 'decorator1' )
95
	 *
96
	 * This would add the decorator named "decorator1" defined by
97
	 * "\Aimeos\Controller\Jobs\Common\Decorator\Decorator1" only to this job controller.
98
	 *
99
	 * @param array List of decorator names
100
	 * @since 2015.09
101
	 * @see controller/jobs/common/decorators/default
102
	 * @see controller/jobs/order/service/delivery/decorators/excludes
103
	 * @see controller/jobs/order/service/delivery/decorators/local
104
	 */
105
106
	/** controller/jobs/order/service/delivery/decorators/local
107
	 * Adds a list of local decorators only to the order service delivery controllers
108
	 *
109
	 * Decorators extend the functionality of a class by adding new aspects
110
	 * (e.g. log what is currently done), executing the methods of the underlying
111
	 * class only in certain conditions (e.g. only for logged in users) or
112
	 * modify what is returned to the caller.
113
	 *
114
	 * This option allows you to wrap local decorators
115
	 * ("\Aimeos\Controller\Jobs\Order\Service\Delivery\Decorator\*") around this job controller.
116
	 *
117
	 *  controller/jobs/order/service/delivery/decorators/local = array( 'decorator2' )
118
	 *
119
	 * This would add the decorator named "decorator2" defined by
120
	 * "\Aimeos\Controller\Jobs\Order\Service\Delivery\Decorator\Decorator2" only to this job
121
	 * controller.
122
	 *
123
	 * @param array List of decorator names
124
	 * @since 2015.09
125
	 * @see controller/jobs/common/decorators/default
126
	 * @see controller/jobs/order/service/delivery/decorators/excludes
127
	 * @see controller/jobs/order/service/delivery/decorators/global
128
	 */
129
130
131
	/**
132
	 * Returns the localized name of the job.
133
	 *
134
	 * @return string Name of the job
135
	 */
136
	public function getName() : string
137
	{
138
		return $this->context()->translate( 'controller/jobs', 'Process order delivery services' );
139
	}
140
141
142
	/**
143
	 * Returns the localized description of the job.
144
	 *
145
	 * @return string Description of the job
146
	 */
147
	public function getDescription() : string
148
	{
149
		return $this->context()->translate( 'controller/jobs', 'Sends paid orders to the ERP system or logistic partner' );
150
	}
151
152
153
	/**
154
	 * Executes the job.
155
	 *
156
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
157
	 */
158
	public function run()
159
	{
160
		$context = $this->context();
161
		$manager = \Aimeos\MShop::create( $context, 'service' );
162
163
		$filter = $manager->filter()->add( ['service.type' => 'delivery'] );
164
		$cursor = $manager->cursor( $filter );
165
166
		while( $items = $manager->iterate( $cursor ) )
167
		{
168
			foreach( $items as $item )
169
			{
170
				try
171
				{
172
					$this->orders( $manager->getProvider( $item, $item->getType() ) );
173
				}
174
				catch( \Exception $e )
175
				{
176
					$str = 'Error while processing service with ID "%1$s": %2$s';
177
					$msg = sprintf( $str, $item->getId(), $e->getMessage() . "\n" . $e->getTraceAsString() );
178
					$context->logger()->error( $msg, 'order/service/delivery' );
179
				}
180
			}
181
		}
182
	}
183
184
185
	/**
186
	 * Returns the domains that should be fetched together with the order data
187
	 *
188
	 * @return array List of domain names
189
	 */
190
	protected function domains() : array
191
	{
192
		/** controller/jobs/order/service/delivery/domains
193
		 * Associated items that should be available too in the order
194
		 *
195
		 * Orders consist of address, coupons, products and services. They can be
196
		 * fetched together with the order items and passed to the delivery service
197
		 * providers. Available domains for those items are:
198
		 *
199
		 * - order/base
200
		 * - order/base/address
201
		 * - order/base/coupon
202
		 * - order/base/product
203
		 * - order/base/service
204
		 *
205
		 * @param array Referenced domain names
206
		 * @since 2022.04
207
		 * @see controller/jobs/order/email/delivery/limit-days
208
		 * @see controller/jobs/order/service/delivery/batch-max
209
		 */
210
		$domains = ['order/base', 'order/base/address', 'order/base/coupon', 'order/base/product', 'order/base/service'];
211
		return $this->context()->config()->get( 'controller/jobs/order/service/delivery/domains', $domains );
212
	}
213
214
215
	/**
216
	 * Returns the payment date until orders should be processed
217
	 *
218
	 * @return string Date/time in "YYYY-MM-DD HH:mm:ss" format
219
	 */
220
	protected function limit() : string
221
	{
222
		/** controller/jobs/order/service/delivery/limit-days
223
		 * Only start the delivery process of orders that were created in the past within the configured number of days
224
		 *
225
		 * The delivery process is normally started immediately after the
226
		 * notification about a successful payment arrived. This option prevents
227
		 * orders from being shipped in case anything went wrong or an update
228
		 * failed and old orders would have been shipped now.
229
		 *
230
		 * @param integer Number of days
231
		 * @since 2014.03
232
		 * @see controller/jobs/order/service/delivery/batch-max
233
		 * @see controller/jobs/order/service/delivery/domains
234
		 */
235
		$days = $this->context()->config()->get( 'controller/jobs/order/service/delivery/limit-days', 90 );
236
		return date( 'Y-m-d 00:00:00', time() - 86400 * $days );
237
	}
238
239
240
	/**
241
	 * Returns the maximum number of orders processed at once
242
	 *
243
	 * @return int Maximum number of items
244
	 */
245
	protected function max() : int
246
	{
247
		/** controller/jobs/order/service/delivery/batch-max
248
		 * Maximum number of orders processed at once by the delivery service provider
249
		 *
250
		 * Orders are sent in batches if the delivery service provider supports it.
251
		 * This setting configures the maximum orders that will be handed over to
252
		 * the delivery service provider at once. Bigger batches an improve the
253
		 * performance but requires more memory.
254
		 *
255
		 * @param integer Number of orders
256
		 * @since 2018.07
257
		 * @see controller/jobs/order/service/delivery/domains
258
		 * @see controller/jobs/order/service/delivery/limit-days
259
		 */
260
		return $this->context()->config()->get( 'controller/jobs/order/service/delivery/batch-max', 100 );
261
	}
262
263
264
	/**
265
	 * Fetches and processes the order items
266
	 *
267
	 * @param \Aimeos\MShop\Service\Provider\Iface $provider Service provider for processing the orders
268
	 */
269
	protected function orders( \Aimeos\MShop\Service\Provider\Iface $provider )
270
	{
271
		$context = $this->context();
272
		$domains = $this->domains();
273
274
		$serviceItem = $provider->getServiceItem();
275
		$manager = \Aimeos\MShop::create( $context, 'order' );
276
277
		$filter = $manager->filter()->slice( 0, $this->max() );
278
		$filter->add( $filter->and( [
279
			$filter->compare( '>=', 'order.datepayment', $this->limit() ),
280
			$filter->compare( '==', 'order.statusdelivery', \Aimeos\MShop\Order\Item\Base::STAT_UNFINISHED ),
281
			$filter->compare( '>=', 'order.statuspayment', \Aimeos\MShop\Order\Item\Base::PAY_PENDING ),
282
			$filter->compare( '==', 'order.base.service.code', $serviceItem->getCode() ),
283
			$filter->compare( '==', 'order.base.service.type', 'delivery' ),
284
		] ) );
285
		$cursor = $manager->cursor( $filter );
286
287
		while( $items = $manager->iterate( $cursor, $domains ) )
288
		{
289
			try
290
			{
291
				$provider->processBatch( $items );
0 ignored issues
show
Bug introduced by
The method processBatch() does not exist on Aimeos\MShop\Service\Provider\Iface. It seems like you code against a sub-type of said class. However, the method does not exist in Aimeos\MShop\Service\Provider\Payment\Iface or Aimeos\MShop\Service\Provider\Decorator\Iface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

291
				$provider->/** @scrutinizer ignore-call */ 
292
               processBatch( $items );
Loading history...
292
293
				$manager->begin();
294
				$manager->save( $items );
295
				$manager->commit();
296
			}
297
			catch( \Exception $e )
298
			{
299
				$str = 'Error while processing orders by delivery service "%1$s": %2$s';
300
				$msg = sprintf( $str, $serviceItem->getId(), $e->getMessage() . "\n" . $e->getTraceAsString() );
301
				$context->logger()->error( $msg, 'order/service/delivery' );
302
			}
303
		}
304
	}
305
}
306