Completed
Push — master ( dbc758...f2332b )
by Aimeos
01:57
created

Standard::createPayment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2018
6
 * @package Controller
7
 * @subpackage Jobs
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Subscription\Process\Renew;
12
13
14
/**
15
 * Job controller for subscription processs renew.
16
 *
17
 * @package Controller
18
 * @subpackage Jobs
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Subscription\Process\Base
22
	implements \Aimeos\Controller\Jobs\Iface
23
{
24
	/**
25
	 * Returns the localized name of the job.
26
	 *
27
	 * @return string Name of the job
28
	 */
29
	public function getName()
30
	{
31
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Subscription process renew' );
32
	}
33
34
35
	/**
36
	 * Returns the localized description of the job.
37
	 *
38
	 * @return string Description of the job
39
	 */
40
	public function getDescription()
41
	{
42
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Renews subscriptions at next date' );
43
	}
44
45
46
	/**
47
	 * Executes the job.
48
	 *
49
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
50
	 */
51
	public function run()
52
	{
53
		$context = $this->getContext();
54
		$config = $context->getConfig();
55
		$logger = $context->getLogger();
56
57
		$names = (array) $config->get( 'controller/common/subscription/process/processors', [] );
58
59
		$date = date( 'Y-m-d' );
60
		$processors = $this->getProcessors( $names );
61
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'subscription' );
62
63
		$search = $manager->createSearch( true );
64
		$expr = [
65
			$search->compare( '<=', 'subscription.datenext', $date ),
66
			$search->combine( '||', [
67
				$search->compare( '==', 'subscription.dateend', null ),
68
				$search->compare( '>', 'subscription.dateend', $date ),
69
			] ),
70
			$search->getConditions(),
71
		];
72
		$search->setConditions( $search->combine( '&&', $expr ) );
73
		$search->setSortations( [$search->sort( '+', 'subscription.id' )] );
74
75
		$start = 0;
76
77
		do
78
		{
79
			$search->setSlice( $start, 100 );
80
			$items = $manager->searchItems( $search );
81
82
			foreach( $items as $item )
83
			{
84
				try
85
				{
86
					$context = $this->createContext( $item->getOrderBaseId() );
87
					$newOrder = $this->createOrderBase( $context, $item );
88
					$newInvoice = $this->createOrderInvoice( $context, $newOrder );
89
90
					try
91
					{
92
						$this->createPayment( $context, $newOrder, $newInvoice );
93
94
						$interval = new \DateInterval( $item->getInterval() );
95
						$item->setDateNext( date_create()->add( $interval )->format( 'Y-m-d' ) );
96
					}
97
					catch( \Exception $e )
98
					{
99
						$item->setReason( \Aimeos\MShop\Subscription\Item\Iface::REASON_PAYMENT );
100
						$item->setDateEnd( date_create()->format( 'Y-m-d' ) );
101
						$manager->saveItem( $item );
102
103
						throw $e;
104
					}
105
106
					$manager->saveItem( $item );
107
108
					foreach( $processors as $processor ) {
109
						$processor->renew( $item, $newInvoice );
110
					}
111
				}
112
				catch( \Exception $e )
113
				{
114
					$msg = 'Unable to process subscription with ID "%1$s": %2$s';
115
					$logger->log( sprintf( $msg, $item->getId(), $e->getMessage() ) );
116
					$logger->log( $e->getTraceAsString() );
117
				}
118
			}
119
120
			$count = count( $items );
121
			$start += $count;
122
		}
123
		while( $count === $search->getSliceSize() );
124
	}
125
126
127
	/**
128
	 * Adds a matching delivery service to the basket
129
	 *
130
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
131
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Order including product and addresses
132
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Order with delivery service added
133
	 */
134
	protected function addDeliveryService( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $basket )
135
	{
136
		$type = \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_DELIVERY;
137
138
		$serviceManager = \Aimeos\MShop\Factory::createManager( $context, 'service' );
139
		$orderServiceManager = \Aimeos\MShop\Factory::createManager( $context, 'order/base/service' );
140
141
		$search = $serviceManager->createSearch( true );
142
		$search->setSortations( [$search->sort( '+', 'service.position' )] );
143
		$search->setConditions( $search->compare( '==', 'service.type.code', $type ) );
144
145
		foreach( $serviceManager->searchItems( $search, ['media', 'price', 'text'] ) as $item )
146
		{
147
			$provider = $serviceManager->getProvider( $item, $item->getType() );
148
149
			if( $provider->isAvailable( $basket ) === true )
150
			{
151
				$orderServiceItem = $orderServiceManager->createItem()->copyFrom( $item );
0 ignored issues
show
Bug introduced by
The method copyFrom() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
152
				$basket->addService( $orderServiceItem, $type );
153
154
				return $basket;
155
			}
156
		}
157
158
		return $basket;
159
	}
160
161
162
	/**
163
	 * Creates a new context based on the order and the customer the subscription belongs to
164
	 *
165
	 * @param string $baseId Unique order base ID
166
	 * @return \Aimeos\MShop\Context\Item\Iface New context object
167
	 */
168
	protected function createContext( $baseId )
169
	{
170
		$context = clone $this->getContext();
171
172
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order/base' );
173
		$baseItem = $manager->getItem( $baseId );
174
175
		$locale = $baseItem->getLocale();
176
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
177
178
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale' );
179
		$locale = $manager->bootstrap( $baseItem->getSiteCode(), $locale->getLanguageId(), $locale->getCurrencyId(), false, $level );
180
181
		$context->setLocale( $locale );
182
183
		try
184
		{
185
			$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
186
			$customerItem = $manager->getItem( $baseItem->getCustomerId(), ['customer/group'] );
187
188
			$context->setUserId( $baseItem->getCustomerId() );
189
			$context->setGroupIds( $customerItem->getGroups() );
190
		}
191
		catch( \Exception $e ) {} // Subscription without account
192
193
		return $context;
194
	}
195
196
197
	/**
198
	 * Creates and stores a new order for the subscribed product
199
	 *
200
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
201
	 * @param \Aimeos\MShop\Subscription\Item\Iface $subscription Subscription item with order base ID and order product ID
202
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Complete order with product, addresses and services saved to the storage
203
	 */
204
	protected function createOrderBase( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Subscription\Item\Iface $subscription )
205
	{
206
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order/base' );
207
208
		$basket = $manager->load( $subscription->getOrderBaseId() );
209
210
		$newBasket = $manager->createItem();
211
		$newBasket->setCustomerId( $basket->getCustomerId() );
0 ignored issues
show
Bug introduced by
The method setCustomerId() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
212
213
		foreach( $basket->getProducts() as $orderProduct )
214
		{
215
			if( $orderProduct->getId() === $subscription->getOrderProductId() )
216
			{
217
				foreach( $orderProduct->getAttributeItems() as $attrItem ) {
218
					$attrItem->setId( null );
219
				}
220
				$newBasket->addProduct( $orderProduct->setId( null ) );
0 ignored issues
show
Bug introduced by
The method addProduct() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
221
			}
222
		}
223
224
		foreach( $basket->getAddresses() as $type => $orderAddress ) {
225
			$newBasket->setAddress( $orderAddress, $type );
0 ignored issues
show
Bug introduced by
The method setAddress() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
226
		}
227
228
		$type = \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_PAYMENT;
229
230
		foreach( $basket->getService( $type ) as $orderService ) {
231
			$newBasket->addService( $orderService, $type );
0 ignored issues
show
Bug introduced by
The method addService() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
232
		}
233
234
		$newBasket = $this->addDeliveryService( $context, $newBasket );
0 ignored issues
show
Documentation introduced by
$newBasket is of type object<Aimeos\MShop\Attribute\Item\Iface>, but the function expects a object<Aimeos\MShop\Order\Item\Base\Iface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
235
236
		return $manager->store( $newBasket );
237
	}
238
239
240
	/**
241
	 * Creates and stores a new invoice for the given order basket
242
	 *
243
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
244
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Complete order with product, addresses and services saved to the storage
245
	 * @return \Aimeos\MShop\Order\Item\Iface New invoice item associated to the order saved to the storage
246
	 */
247
	protected function createOrderInvoice( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $basket )
248
	{
249
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'order' );
250
251
		$item = $manager->createItem();
252
		$item->setBaseId( $basket->getId() );
0 ignored issues
show
Bug introduced by
The method setBaseId() does not seem to exist on object<Aimeos\MShop\Attribute\Item\Iface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
253
		$item->setType( 'subscription' );
0 ignored issues
show
Bug introduced by
The method setType() does not exist on Aimeos\MShop\Attribute\Item\Iface. Did you maybe mean setTypeId()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
254
255
		return $manager->saveItem( $item );
256
	}
257
258
259
	/**
260
	 * Creates a new payment for the given order and invoice
261
	 *
262
	 * @param \Aimeos\MShop\Context\Item\Iface Context object
263
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Complete order with product, addresses and services
264
	 * @param \Aimeos\MShop\Order\Item\Iface New invoice item associated to the order
265
	 */
266
	protected function createPayment( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MShop\Order\Item\Base\Iface $basket,
267
		\Aimeos\MShop\Order\Item\Iface $invoice )
268
	{
269
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'service' );
270
271
		foreach( $basket->getService( \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_PAYMENT ) as $service )
272
		{
273
			$item = $manager->getItem( $service->getServiceId() );
274
			$provider = $manager->getProvider( $item, 'payment' );
275
276
			$provider->repay( $invoice );
277
		}
278
	}
279
}
280