1 | <?php |
||
2 | /* |
||
3 | * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). |
||
4 | * |
||
5 | * Copyright (C) 2019 - 2023 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 | namespace App\Services\ProjectSystem; |
||
22 | |||
23 | use App\Entity\ProjectSystem\Project; |
||
24 | use App\Entity\ProjectSystem\ProjectBOMEntry; |
||
25 | use App\Helpers\Projects\ProjectBuildRequest; |
||
26 | use App\Services\Parts\PartLotWithdrawAddHelper; |
||
27 | |||
28 | class ProjectBuildHelper |
||
29 | { |
||
30 | private PartLotWithdrawAddHelper $withdraw_add_helper; |
||
31 | |||
32 | public function __construct(PartLotWithdrawAddHelper $withdraw_add_helper) |
||
33 | { |
||
34 | $this->withdraw_add_helper = $withdraw_add_helper; |
||
35 | } |
||
36 | |||
37 | /** |
||
38 | * Returns the maximum buildable amount of the given BOM entry based on the stock of the used parts. |
||
39 | * This function only works for BOM entries that are associated with a part. |
||
40 | * @param ProjectBOMEntry $projectBOMEntry |
||
41 | * @return int |
||
42 | */ |
||
43 | public function getMaximumBuildableCountForBOMEntry(ProjectBOMEntry $projectBOMEntry): int |
||
44 | { |
||
45 | $part = $projectBOMEntry->getPart(); |
||
46 | |||
47 | if ($part === null) { |
||
48 | throw new \InvalidArgumentException('This function cannot determine the maximum buildable count for a BOM entry without a part!'); |
||
49 | } |
||
50 | |||
51 | if ($projectBOMEntry->getQuantity() <= 0) { |
||
52 | throw new \RuntimeException('The quantity of the BOM entry must be greater than 0!'); |
||
53 | } |
||
54 | |||
55 | $amount_sum = $part->getAmountSum(); |
||
56 | |||
57 | return (int) floor($amount_sum / $projectBOMEntry->getQuantity()); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Returns the maximum buildable amount of the given project, based on the stock of the used parts in the BOM. |
||
62 | * @param Project $project |
||
63 | * @return int |
||
64 | */ |
||
65 | public function getMaximumBuildableCount(Project $project): int |
||
66 | { |
||
67 | $maximum_buildable_count = PHP_INT_MAX; |
||
68 | foreach ($project->getBOMEntries() as $bom_entry) { |
||
69 | //Skip BOM entries without a part (as we can not determine that) |
||
70 | if (!$bom_entry->isPartBomEntry()) { |
||
71 | continue; |
||
72 | } |
||
73 | |||
74 | //The maximum buildable count for the whole project is the minimum of all BOM entries |
||
75 | $maximum_buildable_count = min($maximum_buildable_count, $this->getMaximumBuildableCountForBOMEntry($bom_entry)); |
||
76 | } |
||
77 | |||
78 | return $maximum_buildable_count; |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Checks if the given project can be build with the current stock. |
||
83 | * This means that the maximum buildable count is greater or equal than the requested $number_of_projects |
||
84 | * @param Project $project |
||
85 | * @parm int $number_of_builds |
||
86 | * @return bool |
||
87 | */ |
||
88 | public function isProjectBuildable(Project $project, int $number_of_builds = 1): bool |
||
89 | { |
||
90 | return $this->getMaximumBuildableCount($project) >= $number_of_builds; |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Check if the given BOM entry can be build with the current stock. |
||
95 | * This means that the maximum buildable count is greater or equal than the requested $number_of_projects |
||
96 | * @param ProjectBOMEntry $bom_entry |
||
97 | * @param int $number_of_builds |
||
98 | * @return bool |
||
99 | */ |
||
100 | public function isBOMEntryBuildable(ProjectBOMEntry $bom_entry, int $number_of_builds = 1): bool |
||
101 | { |
||
102 | return $this->getMaximumBuildableCountForBOMEntry($bom_entry) >= $number_of_builds; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Returns the project BOM entries for which parts are missing in the stock for the given number of builds |
||
107 | * @param Project $project The project for which the BOM entries should be checked |
||
108 | * @param int $number_of_builds How often should the project be build? |
||
109 | * @return ProjectBOMEntry[] |
||
110 | */ |
||
111 | public function getNonBuildableProjectBomEntries(Project $project, int $number_of_builds = 1): array |
||
112 | { |
||
113 | if ($number_of_builds < 1) { |
||
114 | throw new \InvalidArgumentException('The number of builds must be greater than 0!'); |
||
115 | } |
||
116 | |||
117 | $non_buildable_entries = []; |
||
118 | |||
119 | foreach ($project->getBomEntries() as $bomEntry) { |
||
120 | $part = $bomEntry->getPart(); |
||
121 | |||
122 | //Skip BOM entries without a part (as we can not determine that) |
||
123 | if ($part === null) { |
||
124 | continue; |
||
125 | } |
||
126 | |||
127 | $amount_sum = $part->getAmountSum(); |
||
128 | |||
129 | if ($amount_sum < $bomEntry->getQuantity() * $number_of_builds) { |
||
130 | $non_buildable_entries[] = $bomEntry; |
||
131 | } |
||
132 | } |
||
133 | |||
134 | return $non_buildable_entries; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Withdraw the parts from the stock using the given ProjectBuildRequest and create the build parts entries, if needed. |
||
139 | * The ProjectBuildRequest has to be validated before!! |
||
140 | * You have to flush changes to DB afterwards |
||
141 | * @param ProjectBuildRequest $buildRequest |
||
142 | * @return void |
||
143 | */ |
||
144 | public function doBuild(ProjectBuildRequest $buildRequest): void |
||
145 | { |
||
146 | $message = $buildRequest->getComment(); |
||
147 | $message .= ' (Project build: '.$buildRequest->getProject()->getName().')'; |
||
148 | |||
149 | foreach ($buildRequest->getPartBomEntries() as $bom_entry) { |
||
150 | foreach ($buildRequest->getPartLotsForBOMEntry($bom_entry) as $part_lot) { |
||
151 | $amount = $buildRequest->getLotWithdrawAmount($part_lot); |
||
152 | if ($amount > 0) { |
||
153 | $this->withdraw_add_helper->withdraw($part_lot, $amount, $message); |
||
154 | } |
||
155 | } |
||
156 | } |
||
157 | |||
158 | if ($buildRequest->getAddBuildsToBuildsPart()) { |
||
159 | $this->withdraw_add_helper->add($buildRequest->getBuildsPartLot(), $buildRequest->getNumberOfBuilds(), $message); |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
160 | } |
||
161 | } |
||
162 | } |