Passed
Push — master ( ccdac1...a3c626 )
by Jan
04:20
created

Pricedetail::__clone()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
declare(strict_types=1);
22
23
/**
24
 * part-db version 0.1
25
 * Copyright (C) 2005 Christoph Lechner
26
 * http://www.cl-projects.de/.
27
 *
28
 * part-db version 0.2+
29
 * Copyright (C) 2009 K. Jacobs and others (see authors.php)
30
 * http://code.google.com/p/part-db/
31
 *
32
 * Part-DB Version 0.4+
33
 * Copyright (C) 2016 - 2019 Jan Böhmer
34
 * https://github.com/jbtronics
35
 *
36
 * This program is free software; you can redistribute it and/or
37
 * modify it under the terms of the GNU General Public License
38
 * as published by the Free Software Foundation; either version 2
39
 * of the License, or (at your option) any later version.
40
 *
41
 * This program is distributed in the hope that it will be useful,
42
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44
 * GNU General Public License for more details.
45
 *
46
 * You should have received a copy of the GNU General Public License
47
 * along with this program; if not, write to the Free Software
48
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
49
 */
50
51
namespace App\Entity\PriceInformations;
52
53
use App\Entity\Base\AbstractDBElement;
54
use App\Entity\Base\TimestampTrait;
55
use App\Entity\Contracts\TimeStampableInterface;
56
use App\Validator\Constraints\Selectable;
57
use Doctrine\ORM\Mapping as ORM;
58
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
59
use Symfony\Component\Validator\Constraints as Assert;
60
61
/**
62
 * Class Pricedetail.
63
 *
64
 * @ORM\Entity()
65
 * @ORM\Table("`pricedetails`")
66
 * @ORM\HasLifecycleCallbacks()
67
 * @UniqueEntity(fields={"orderdetail", "min_discount_quantity"})
68
 */
69
class Pricedetail extends AbstractDBElement implements TimeStampableInterface
70
{
71
    use TimestampTrait;
72
73
    public const PRICE_PRECISION = 5;
74
75
    /**
76
     * @var string The price related to the detail. (Given in the selected currency)
77
     * @ORM\Column(type="decimal", precision=11, scale=5)
78
     * @Assert\Positive()
79
     */
80
    protected $price = '0.0';
81
82
    /**
83
     * @var ?Currency The currency used for the current price information.
84
     *                If this is null, the global base unit is assumed.
85
     * @ORM\ManyToOne(targetEntity="Currency")
86
     * @ORM\JoinColumn(name="id_currency", referencedColumnName="id", nullable=true)
87
     * @Selectable()
88
     */
89
    protected $currency;
90
91
    /**
92
     * @var float
93
     * @ORM\Column(type="float")
94
     * @Assert\Positive()
95
     */
96
    protected $price_related_quantity = 1.0;
97
98
    /**
99
     * @var float
100
     * @ORM\Column(type="float")
101
     * @Assert\Positive()
102
     */
103
    protected $min_discount_quantity = 1.0;
104
105
    /**
106
     * @var bool
107
     * @ORM\Column(type="boolean")
108
     */
109
    protected $manual_input = true;
110
111
    /**
112
     * @var Orderdetail|null
113
     * @ORM\ManyToOne(targetEntity="Orderdetail", inversedBy="pricedetails")
114
     * @ORM\JoinColumn(name="orderdetails_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
115
     * @Assert\NotNull()
116
     */
117
    protected $orderdetail;
118
119
    public function __construct()
120
    {
121
        bcscale(static::PRICE_PRECISION);
122
    }
123
124
    /********************************************************************************
125
     *
126
     *   Getters
127
     *
128
     *********************************************************************************/
129
130
    /**
131
     * Get the orderdetail to which this pricedetail belongs to this pricedetails.
132
     *
133
     * @return Orderdetail the orderdetail this price belongs to
134
     */
135
    public function getOrderdetail(): Orderdetail
136
    {
137
        return $this->orderdetail;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->orderdetail could return the type null which is incompatible with the type-hinted return App\Entity\PriceInformations\Orderdetail. Consider adding an additional type-check to rule them out.
Loading history...
138
    }
139
140
    /**
141
     * Returns the price associated with this pricedetail.
142
     * It is given in current currency and for the price related quantity.
143
     *
144
     * @return string the price as string, like returned raw from DB
145
     */
146
    public function getPrice(): string
147
    {
148
        return $this->price;
149
    }
150
151
    /**
152
     * Get the price for a single unit in the currency associated with this price detail.
153
     *
154
     * @param float|string $multiplier The returned price (float or string) will be multiplied
155
     *                                 with this multiplier.
156
     *
157
     *     You will get the price for $multiplier parts. If you want the price which is stored
158
     *          in the database, you have to pass the "price_related_quantity" count as $multiplier.
159
     *
160
     * @return string the price as a bcmath string
161
     */
162
    public function getPricePerUnit($multiplier = 1.0): string
163
    {
164
        $multiplier = (string) $multiplier;
165
        $tmp = bcmul($this->price, $multiplier, static::PRICE_PRECISION);
166
167
        return bcdiv($tmp, (string) $this->price_related_quantity, static::PRICE_PRECISION);
0 ignored issues
show
Bug Best Practice introduced by
The expression return bcdiv($tmp, (stri...tatic::PRICE_PRECISION) could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
168
        //return ($this->price * $multiplier) / $this->price_related_quantity;
169
    }
170
171
    /**
172
     *  Get the price related quantity.
173
     *
174
     * This is the quantity, for which the price is valid.
175
     * The amount is measured in part unit.
176
     *
177
     * @return float the price related quantity
178
     *
179
     * @see Pricedetail::setPriceRelatedQuantity()
180
     */
181
    public function getPriceRelatedQuantity(): float
182
    {
183
        if ($this->orderdetail && $this->orderdetail->getPart() && ! $this->orderdetail->getPart()->useFloatAmount()) {
184
            $tmp = round($this->price_related_quantity);
185
186
            return $tmp < 1 ? 1 : $tmp;
187
        }
188
189
        return $this->price_related_quantity;
190
    }
191
192
    /**
193
     *  Get the minimum discount quantity.
194
     *
195
     * "Minimum discount quantity" means the minimum order quantity for which the price
196
     * of this orderdetails is valid.
197
     *
198
     * The amount is measured in part unit.
199
     *
200
     * @return float the minimum discount quantity
201
     *
202
     * @see Pricedetail::setMinDiscountQuantity()
203
     */
204
    public function getMinDiscountQuantity(): float
205
    {
206
        if ($this->orderdetail && $this->orderdetail->getPart() && ! $this->orderdetail->getPart()->useFloatAmount()) {
207
            $tmp = round($this->min_discount_quantity);
208
209
            return $tmp < 1 ? 1 : $tmp;
210
        }
211
212
        return $this->min_discount_quantity;
213
    }
214
215
    /**
216
     * Returns the currency associated with this price information.
217
     * Returns null, if no specific currency is selected and the global base currency should be assumed.
218
     */
219
    public function getCurrency(): ?Currency
220
    {
221
        return $this->currency;
222
    }
223
224
    /********************************************************************************
225
     *
226
     *   Setters
227
     *
228
     *********************************************************************************/
229
230
    /**
231
     * Sets the orderdetail to which this pricedetail belongs to.
232
     *
233
     * @param  Orderdetail  $orderdetail
234
     * @return $this
235
     */
236
    public function setOrderdetail(Orderdetail $orderdetail): self
237
    {
238
        $this->orderdetail = $orderdetail;
239
240
        return $this;
241
    }
242
243
    /**
244
     * Sets the currency associated with the price informations.
245
     * Set to null, to use the global base currency.
246
     *
247
     * @param  Currency|null  $currency
248
     * @return Pricedetail
249
     */
250
    public function setCurrency(?Currency $currency): self
251
    {
252
        $this->currency = $currency;
253
254
        return $this;
255
    }
256
257
    /**
258
     *  Set the price.
259
     *
260
     * @param string $new_price the new price as a float number
261
     *
262
     *      * This is the price for "price_related_quantity" parts!!
263
     *              * Example: if "price_related_quantity" is '10',
264
     *                  you have to set here the price for 10 parts!
265
     * @return $this
266
     */
267
    public function setPrice(string $new_price): self
268
    {
269
        //Assert::natural($new_price, 'The new price must be positive! Got %s!');
270
271
        $this->price = $new_price;
272
273
        return $this;
274
    }
275
276
    /**
277
     *  Set the price related quantity.
278
     *
279
     * This is the quantity, for which the price is valid.
280
     *
281
     * Example:
282
     * If 100pcs costs 20$, you have to set the price to 20$ and the price related
283
     * quantity to 100. The single price (20$/100 = 0.2$) will be calculated automatically.
284
     *
285
     * @param float $new_price_related_quantity the price related quantity
286
     *
287
     * @return $this
288
     */
289
    public function setPriceRelatedQuantity(float $new_price_related_quantity): self
290
    {
291
        $this->price_related_quantity = $new_price_related_quantity;
292
293
        return $this;
294
    }
295
296
    /**
297
     *  Set the minimum discount quantity.
298
     *
299
     * "Minimum discount quantity" means the minimum order quantity for which the price
300
     * of this orderdetails is valid. This way, you're able to use different prices
301
     * for different order quantities (quantity discount!).
302
     *
303
     *  Example:
304
     *      - 1-9pcs costs 10$: set price to 10$/pcs and minimum discount quantity to 1
305
     *      - 10-99pcs costs 9$: set price to 9$/pcs and minimum discount quantity to 10
306
     *      - 100pcs or more costs 8$: set price/pcs to 8$ and minimum discount quantity to 100
307
     *
308
     * (Each of this examples would be an own Pricedetails-object.
309
     * So the orderdetails would have three Pricedetails for one supplier.)
310
     *
311
     * @param float $new_min_discount_quantity the minimum discount quantity
312
     * @return $this
313
     */
314
    public function setMinDiscountQuantity(float $new_min_discount_quantity): self
315
    {
316
        $this->min_discount_quantity = $new_min_discount_quantity;
317
318
        return $this;
319
    }
320
321
    /**
322
     * Returns the ID as an string, defined by the element class.
323
     * This should have a form like P000014, for a part with ID 14.
324
     *
325
     * @return string The ID as a string;
326
     */
327
    public function getIDString(): string
328
    {
329
        return 'PD'.sprintf('%06d', $this->getID());
330
    }
331
332
    public function __clone()
333
    {
334
        if ($this->id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->id of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
335
           $this->addedDate = null;
336
        }
337
        parent::__clone();
338
    }
339
}
340