Skip to content

Commit 658c8d3

Browse files
author
Fabian Wunsch
committed
First order details draft
1 parent 756152d commit 658c8d3

File tree

13 files changed

+171
-8
lines changed

13 files changed

+171
-8
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use App\Migration\AbstractMultiPlatformMigration;
8+
use Doctrine\DBAL\Schema\Schema;
9+
10+
final class Version20240905085300 extends AbstractMultiPlatformMigration
11+
{
12+
public function getDescription(): string
13+
{
14+
return 'Added order fields';
15+
}
16+
17+
public function mySQLUp(Schema $schema): void
18+
{
19+
$this->addSql('ALTER TABLE parts ADD orderamount DOUBLE PRECISION NOT NULL DEFAULT 0, ADD orderDate DATETIME');
20+
}
21+
22+
public function mySQLDown(Schema $schema): void
23+
{
24+
$this->addSql('ALTER TABLE `parts` DROP orderamount, DROP orderDate');
25+
}
26+
27+
public function sqLiteUp(Schema $schema): void
28+
{
29+
$this->addSql('ALTER TABLE parts ADD COLUMN orderamount DOUBLE PRECISION NOT NULL DEFAULT 0');
30+
$this->addSql('ALTER TABLE parts ADD COLUMN orderDate DATETIME');
31+
}
32+
33+
public function sqLiteDown(Schema $schema): void
34+
{
35+
$error;
36+
// TODO: implement backwards migration for SQlite
37+
}
38+
}

src/DataTables/Filters/Constraints/Part/LessThanDesiredConstraint.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ public function apply(QueryBuilder $queryBuilder): void
4848

4949
//If value is true, we want to filter for parts with stock < desired stock
5050
if ($this->value) {
51-
$queryBuilder->andHaving( $this->property . ' < part.minamount');
51+
$queryBuilder->andHaving($this->property . ' + part.orderamount < part.minamount');
5252
} else {
53-
$queryBuilder->andHaving($this->property . ' >= part.minamount');
53+
$queryBuilder->andHaving($this->property . ' + part.orderamount >= part.minamount');
5454
}
5555
}
5656
}

src/DataTables/Filters/PartFilter.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class PartFilter implements FilterInterface
5858
public readonly TextConstraint $comment;
5959
public readonly TagsConstraint $tags;
6060
public readonly NumberConstraint $minAmount;
61+
public readonly NumberConstraint $orderAmount;
62+
public readonly DateTimeConstraint $orderDelivery;
6163
public readonly BooleanConstraint $favorite;
6264
public readonly BooleanConstraint $needsReview;
6365
public readonly NumberConstraint $mass;
@@ -120,6 +122,8 @@ public function __construct(NodesListBuilder $nodesListBuilder)
120122
$this->lastModified = new DateTimeConstraint('part.lastModified');
121123

122124
$this->minAmount = new NumberConstraint('part.minamount');
125+
$this->orderAmount = new NumberConstraint('part.orderamount');
126+
$this->orderDelivery = new DateTimeConstraint('part.orderDelivery');
123127
/* We have to use an IntConstraint here because otherwise we get just an empty result list when applying the filter
124128
This seems to be related to the fact, that PDO does not have an float parameter type and using string type does not work in this situation (at least in SQLite)
125129
TODO: Find a better solution here

src/DataTables/PartsDataTable.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,15 @@ public function configure(DataTable $dataTable, array $options): void
151151
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
152152
$context->getPartUnit())),
153153
])
154+
->add('orderamount', TextColumn::class, [
155+
'label' => $this->translator->trans('part.table.orderamount'),
156+
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
157+
$context->getPartUnit())),
158+
])
159+
->add('orderDelivery', LocaleDateTimeColumn::class, [
160+
'label' => $this->translator->trans('part.table.orderDelivery'),
161+
'timeFormat' => 'none',
162+
])
154163
->add('partUnit', TextColumn::class, [
155164
'label' => $this->translator->trans('part.table.partUnit'),
156165
'orderField' => 'NATSORT(_partUnit.name)',

src/Entity/Parts/Part.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
use Doctrine\Common\Collections\ArrayCollection;
6060
use Doctrine\Common\Collections\Collection;
6161
use Doctrine\ORM\Mapping as ORM;
62+
use Doctrine\DBAL\Types\Types;
6263
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
6364
use Symfony\Component\Serializer\Annotation\Groups;
6465
use Symfony\Component\Validator\Constraints as Assert;
@@ -99,9 +100,9 @@
99100
#[ApiFilter(PartStoragelocationFilter::class, properties: ["storage_location"])]
100101
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "tags", "manufacturer_product_number"])]
101102
#[ApiFilter(BooleanFilter::class, properties: ["favorite" , "needs_review"])]
102-
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount"])]
103+
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount", "orderamount"])]
103104
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
104-
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
105+
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'orderDelivery', 'addedDate', 'lastModified'])]
105106
class Part extends AttachmentContainingDBElement
106107
{
107108
use AdvancedPropertyTrait;
@@ -124,6 +125,15 @@ class Part extends AttachmentContainingDBElement
124125
#[UniqueObjectCollection(fields: ['name', 'group', 'element'])]
125126
protected Collection $parameters;
126127

128+
/**
129+
* @var \DateTimeInterface|null Set a time when the new order will arive.
130+
* Set to null, if there is no known date or no order.
131+
*/
132+
#[Groups(['extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])]
133+
#[ORM\Column(name: 'orderDelivery', type: Types::DATETIME_MUTABLE, nullable: true)]
134+
#[Year2038BugWorkaround]
135+
protected ?\DateTimeInterface $orderDelivery = null;
136+
127137

128138
/** *************************************************************
129139
* Overridden properties
@@ -214,6 +224,26 @@ public function __clone()
214224
parent::__clone();
215225
}
216226

227+
/**
228+
* Gets the expected delivery date of the part. Returns null, if no delivery is due.
229+
*/
230+
public function getOrderDelivery(): ?\DateTimeInterface
231+
{
232+
return $this->orderDelivery;
233+
}
234+
235+
/**
236+
* Sets the expected delivery date of the part. Set to null, if no delivery is due.
237+
*
238+
*
239+
*/
240+
public function setOrderDelivery(?\DateTimeInterface $orderDelivery): self
241+
{
242+
$this->orderDelivery = $orderDelivery;
243+
244+
return $this;
245+
}
246+
217247
#[Assert\Callback]
218248
public function validate(ExecutionContextInterface $context, $payload): void
219249
{

src/Entity/Parts/PartTraits/InstockTrait.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ trait InstockTrait
5555
#[ORM\Column(type: Types::FLOAT)]
5656
protected float $minamount = 0;
5757

58+
/**
59+
* @var float The number of already ordered units
60+
*/
61+
#[Assert\PositiveOrZero]
62+
#[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])]
63+
#[ORM\Column(type: Types::FLOAT)]
64+
protected float $orderamount = 0;
65+
5866
/**
5967
* @var ?MeasurementUnit the unit in which the part's amount is measured
6068
*/
@@ -137,6 +145,21 @@ public function getMinAmount(): float
137145
return round($this->minamount);
138146
}
139147

148+
/**
149+
* Get the count of parts which are already ordered.
150+
* If an integer-based part unit is selected, the value will be rounded to integers.
151+
*
152+
* @return float count of parts which are already ordered
153+
*/
154+
public function getOrderAmount(): float
155+
{
156+
if ($this->useFloatAmount()) {
157+
return $this->orderamount;
158+
}
159+
160+
return round($this->orderamount);
161+
}
162+
140163
/**
141164
* Checks if this part uses the float amount .
142165
* This setting is based on the part unit (see MeasurementUnit->isInteger()).
@@ -158,7 +181,7 @@ public function useFloatAmount(): bool
158181
*/
159182
public function isNotEnoughInstock(): bool
160183
{
161-
return $this->getAmountSum() < $this->getMinAmount();
184+
return ($this->getAmountSum() + $this->getOrderAmount()) < $this->getMinAmount();
162185
}
163186

164187
/**
@@ -238,4 +261,19 @@ public function setMinAmount(float $new_minamount): self
238261

239262
return $this;
240263
}
264+
265+
/**
266+
* Set the amount of already ordered parts.
267+
* See getPartUnit() for the associated unit.
268+
*
269+
* @param float $new_orderamount the new count of parts are already ordered
270+
*
271+
* @return $this
272+
*/
273+
public function setOrderAmount(float $new_orderamount): self
274+
{
275+
$this->orderamount = $new_orderamount;
276+
277+
return $this;
278+
}
241279
}

src/Form/Filters/PartFilterType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
202202
'min' => 0,
203203
]);
204204

205+
$builder->add('orderAmount', NumberConstraintType::class, [
206+
'label' => 'part.edit.orderstock',
207+
'min' => 0,
208+
]);
209+
210+
$builder->add('orderDelivery', DateTimeConstraintType::class, [
211+
'label' => 'part.edit.orderDelivery',
212+
'input_type' => DateType::class,
213+
]);
214+
205215
$builder->add('lotCount', NumberConstraintType::class, [
206216
'label' => 'part.filter.lot_count',
207217
'min' => 0,

src/Form/Part/PartBaseType.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
use Symfony\Component\Form\AbstractType;
4545
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
4646
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
47+
use Symfony\Component\Form\Extension\Core\Type\DateType;
4748
use Symfony\Component\Form\Extension\Core\Type\EnumType;
4849
use Symfony\Component\Form\Extension\Core\Type\ResetType;
4950
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@@ -95,6 +96,21 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
9596
'label' => 'part.edit.mininstock',
9697
'measurement_unit' => $part->getPartUnit(),
9798
])
99+
->add('orderAmount', SIUnitType::class, [
100+
'attr' => [
101+
'min' => 0,
102+
'placeholder' => 'part.editmininstock.placeholder',
103+
],
104+
'label' => 'part.edit.orderstock',
105+
'measurement_unit' => $part->getPartUnit(),
106+
])
107+
->add('orderDelivery', DateType::class, [
108+
'label' => 'part.edit.orderDelivery',
109+
'attr' => [],
110+
'widget' => 'single_text',
111+
'model_timezone' => 'UTC',
112+
'required' => false,
113+
])
98114
->add('category', StructuralEntityType::class, [
99115
'class' => Category::class,
100116
'allow_add' => $this->security->isGranted('@categories.create'),

src/Serializer/PartNormalizer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ public function denormalize($data, string $type, string $format = null, array $c
129129
if (empty($data['minamount'])) {
130130
$data['minamount'] = 0.0;
131131
}
132+
if (empty($data['orderamount'])) {
133+
$data['orderamount'] = 0.0;
134+
}
132135

133136
$context[self::ALREADY_CALLED] = true;
134137

src/Services/LabelSystem/SandboxedTwigFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ final class SandboxedTwigFactory
133133
Supplier::class => ['getShippingCosts', 'getDefaultCurrency'],
134134
Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getIpn', 'getProviderReference',
135135
'getDescription', 'getComment', 'isFavorite', 'getCategory', 'getFootprint',
136-
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
136+
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getOrderAmount', 'getOrderDate', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
137137
'getManufacturerProductUrl', 'getCustomProductURL', 'getManufacturingStatus', 'getManufacturer',
138138
'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete',
139139
'getParameters', 'getGroupedParameters',

0 commit comments

Comments
 (0)