Skip to content

Commit 62754bd

Browse files
author
Fabian Wunsch
committed
First order details draft
1 parent 1a0fab0 commit 62754bd

File tree

13 files changed

+170
-7
lines changed

13 files changed

+170
-7
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
@@ -59,6 +59,8 @@ class PartFilter implements FilterInterface
5959
public readonly TextConstraint $comment;
6060
public readonly TagsConstraint $tags;
6161
public readonly NumberConstraint $minAmount;
62+
public readonly NumberConstraint $orderAmount;
63+
public readonly DateTimeConstraint $orderDelivery;
6264
public readonly BooleanConstraint $favorite;
6365
public readonly BooleanConstraint $needsReview;
6466
public readonly NumberConstraint $mass;
@@ -124,6 +126,8 @@ public function __construct(NodesListBuilder $nodesListBuilder)
124126
$this->lastModified = new DateTimeConstraint('part.lastModified');
125127

126128
$this->minAmount = new NumberConstraint('part.minamount');
129+
$this->orderAmount = new NumberConstraint('part.orderamount');
130+
$this->orderDelivery = new DateTimeConstraint('part.orderDelivery');
127131
/* We have to use an IntConstraint here because otherwise we get just an empty result list when applying the filter
128132
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)
129133
TODO: Find a better solution here

src/DataTables/PartsDataTable.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ public function configure(DataTable $dataTable, array $options): void
155155
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
156156
$context->getPartUnit())),
157157
])
158+
->add('orderamount', TextColumn::class, [
159+
'label' => $this->translator->trans('part.table.orderamount'),
160+
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
161+
$context->getPartUnit())),
162+
])
163+
->add('orderDelivery', LocaleDateTimeColumn::class, [
164+
'label' => $this->translator->trans('part.table.orderDelivery'),
165+
'timeFormat' => 'none',
166+
])
158167
->add('partUnit', TextColumn::class, [
159168
'label' => $this->translator->trans('part.table.partUnit'),
160169
'orderField' => 'NATSORT(_partUnit.name)',

src/Entity/Parts/Part.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
use Doctrine\Common\Collections\ArrayCollection;
6161
use Doctrine\Common\Collections\Collection;
6262
use Doctrine\ORM\Mapping as ORM;
63+
use Doctrine\DBAL\Types\Types;
6364
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
6465
use Symfony\Component\Serializer\Annotation\Groups;
6566
use Symfony\Component\Validator\Constraints as Assert;
@@ -101,9 +102,9 @@
101102
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "manufacturer_product_number"])]
102103
#[ApiFilter(TagFilter::class, properties: ["tags"])]
103104
#[ApiFilter(BooleanFilter::class, properties: ["favorite" , "needs_review"])]
104-
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount"])]
105+
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount", "orderamount"])]
105106
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
106-
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
107+
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'orderDelivery', 'addedDate', 'lastModified'])]
107108
class Part extends AttachmentContainingDBElement
108109
{
109110
use AdvancedPropertyTrait;
@@ -126,6 +127,15 @@ class Part extends AttachmentContainingDBElement
126127
#[UniqueObjectCollection(fields: ['name', 'group', 'element'])]
127128
protected Collection $parameters;
128129

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

130140
/** *************************************************************
131141
* Overridden properties
@@ -216,6 +226,26 @@ public function __clone()
216226
parent::__clone();
217227
}
218228

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

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
@@ -45,6 +45,7 @@
4545
use Symfony\Component\Form\AbstractType;
4646
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
4747
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
48+
use Symfony\Component\Form\Extension\Core\Type\DateType;
4849
use Symfony\Component\Form\Extension\Core\Type\EnumType;
4950
use Symfony\Component\Form\Extension\Core\Type\ResetType;
5051
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@@ -96,6 +97,21 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
9697
'label' => 'part.edit.mininstock',
9798
'measurement_unit' => $part->getPartUnit(),
9899
])
100+
->add('orderAmount', SIUnitType::class, [
101+
'attr' => [
102+
'min' => 0,
103+
'placeholder' => 'part.editmininstock.placeholder',
104+
],
105+
'label' => 'part.edit.orderstock',
106+
'measurement_unit' => $part->getPartUnit(),
107+
])
108+
->add('orderDelivery', DateType::class, [
109+
'label' => 'part.edit.orderDelivery',
110+
'attr' => [],
111+
'widget' => 'single_text',
112+
'model_timezone' => 'UTC',
113+
'required' => false,
114+
])
99115
->add('category', StructuralEntityType::class, [
100116
'class' => Category::class,
101117
'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
@@ -136,6 +136,9 @@ public function denormalize($data, string $type, ?string $format = null, array $
136136
if (empty($data['minamount'])) {
137137
$data['minamount'] = 0.0;
138138
}
139+
if (empty($data['orderamount'])) {
140+
$data['orderamount'] = 0.0;
141+
}
139142

140143
$context[self::ALREADY_CALLED] = true;
141144

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)