PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
← All changes | app/Http/Requests/ProductVariationRequest.php +97 -15 1.5.4 → 1.6.5 View file →
@@ -2,8 +2,9 @@
2 2
3 3 namespace FluentCart\App\Http\Requests;
4 4
5 5 use FluentCart\App\Helpers\Helper;
6 +use FluentCart\App\Http\Rules\RequiredWhenRule;
6 7 use FluentCart\Framework\Foundation\RequestGuard;
7 8 use FluentCart\Framework\Support\Arr;
8 9
9 10 class ProductVariationRequest extends RequestGuard
@@ -74,8 +75,32 @@
74 75 * @return array
75 76 */
76 77 public function rules()
77 78 {
79 + // total_stock / available / committed / on_hold are `INT(11) NULL DEFAULT 0`
80 + // (ProductVariationMigrator), so an empty counter is a legitimate stored state for
81 + // a variation that never tracked stock. ProductEditModel::createOrUpdatePricing()
82 + // posts the variation back exactly as the drawer loaded it, NULLs included, so
83 + // demanding a number unconditionally rejected a plain price edit on such a row.
84 + //
85 + // This cannot be expressed as `nullable|numeric`: Validator::filterExcludeables()
86 + // drops EVERY rule for a falsy value the moment `nullable` is present, which
87 + // would disarm the conditional requirement too. It cannot sit beside a
88 + // `required_if` string either — filterRequiredIf() discarded this closure along
89 + // with every other rule whenever tracking was off, leaving the guard inert. The
90 + // requirement is a RequiredWhenRule closure below for that reason.
91 + $numericWhenProvided = function ($attribute, $value) {
92 + if ($value === null || $value === '') {
93 + return null;
94 + }
95 +
96 + if (!is_numeric($value)) {
97 + return esc_html__('Stock quantity must be a number.', 'fluent-cart');
98 + }
99 +
100 + return null;
101 + };
102 +
78 103 return [
79 104 'variants.variation_title' => 'required|sanitizeText|maxLength:200',
80 105 'variants.sku' => 'nullable|sanitizeText|maxLength:30|unique:fct_product_variations,sku' . ($this->get('variants.id') ? ',' . $this->get('variants.id') : ''),
81 106 'variants.item_price' => 'nullable|numeric|min:0',
@@ -93,9 +118,15 @@
93 118 return null;
94 119 },
95 120 ],
96 121 'variants.manage_cost' => 'nullable|sanitizeText|maxLength:10',
97 - 'variants.item_cost' => 'required_if:variants.manage_cost,true',
122 + 'variants.item_cost' => [
123 + RequiredWhenRule::make(
124 + 'variants.manage_cost',
125 + 'true',
126 + esc_html__('Item cost is required.', 'fluent-cart')
127 + ),
128 + ],
98 129 'variants.fulfillment_type' => 'required|sanitizeText|maxLength:100',
99 130 'variants.shipping_class' => function ($attr, $value) {
100 131 if ($value && !(\FluentCart\App\Models\ShippingClass::find(intval($value)))) {
101 132 return __('The selected shipping class does not exist.', 'fluent-cart');
@@ -103,11 +134,35 @@
103 134 return null;
104 135 },
105 136
106 137 'variants.manage_stock' => 'nullable|numeric',
107 - 'variants.stock_status' => 'required_if:variants.manage_stock,1|sanitizeText|maxLength:50',
108 - 'variants.total_stock' => 'required|numeric',
109 - 'variants.available' => 'required|numeric',
138 + 'variants.stock_status' => [
139 + RequiredWhenRule::make(
140 + 'variants.manage_stock',
141 + '1',
142 + esc_html__('Stock status is required.', 'fluent-cart')
143 + ),
144 + 'sanitizeText',
145 + 'maxLength:50',
146 + ],
147 + // Quantities are only demanded once tracking is actually on, mirroring
148 + // stock_status directly above.
149 + 'variants.total_stock' => [
150 + RequiredWhenRule::make(
151 + 'variants.manage_stock',
152 + '1',
153 + esc_html__('Stock quantity is required when inventory tracking is on.', 'fluent-cart')
154 + ),
155 + $numericWhenProvided,
156 + ],
157 + 'variants.available' => [
158 + RequiredWhenRule::make(
159 + 'variants.manage_stock',
160 + '1',
161 + esc_html__('Available quantity is required when inventory tracking is on.', 'fluent-cart')
162 + ),
163 + $numericWhenProvided,
164 + ],
110 165 // 'variants.available' => [
111 166 // 'required',
112 167 // 'numeric',
113 168 // function ($attribute, $value, $fail) {
@@ -116,10 +171,12 @@
116 171 // }
117 172 // return null;
118 173 // },
119 174 // ],
120 - 'variants.committed' => 'required|numeric',
121 - 'variants.on_hold' => 'required|numeric',
175 + // Ledger columns the merchant never edits — they are maintained by the stock
176 + // listeners, so they only have to be a number when the payload carries one.
177 + 'variants.committed' => [$numericWhenProvided],
178 + 'variants.on_hold' => [$numericWhenProvided],
122 179
123 180 'variants.serial_index' => 'nullable|numeric',
124 181
125 182 'variants.other_info' => 'required|array',
@@ -149,13 +206,43 @@
149 206 }
150 207 return null;
151 208 },
152 209 ],
153 - 'variants.other_info.repeat_interval' => 'required_if:variants.other_info.payment_type,subscription|sanitizeText|maxLength:100',
210 + 'variants.other_info.repeat_interval' => [
211 + RequiredWhenRule::make(
212 + 'variants.other_info.payment_type',
213 + 'subscription',
214 + esc_html__('Interval is required.', 'fluent-cart')
215 + ),
216 + 'sanitizeText',
217 + 'maxLength:100',
218 + ],
154 219 'variants.other_info.billing_summary' => 'nullable|sanitizeTextArea|maxLength:255',
155 - 'variants.other_info.manage_setup_fee' => 'required_if:variants.other_info.payment_type,subscription|sanitizeText|maxLength:100',
156 - 'variants.other_info.signup_fee' => 'required_if:variants.other_info.manage_setup_fee,yes',
157 - 'variants.other_info.signup_fee_name' => 'required_if:variants.other_info.manage_setup_fee,yes|sanitizeText|maxLength:100',
220 + 'variants.other_info.manage_setup_fee' => [
221 + RequiredWhenRule::make(
222 + 'variants.other_info.payment_type',
223 + 'subscription',
224 + esc_html__('Setup Fee option is required.', 'fluent-cart')
225 + ),
226 + 'sanitizeText',
227 + 'maxLength:100',
228 + ],
229 + 'variants.other_info.signup_fee' => [
230 + RequiredWhenRule::make(
231 + 'variants.other_info.manage_setup_fee',
232 + 'yes',
233 + esc_html__('Setup Fee Amount is required.', 'fluent-cart')
234 + ),
235 + ],
236 + 'variants.other_info.signup_fee_name' => [
237 + RequiredWhenRule::make(
238 + 'variants.other_info.manage_setup_fee',
239 + 'yes',
240 + esc_html__('Setup Fee Name is required.', 'fluent-cart')
241 + ),
242 + 'sanitizeText',
243 + 'maxLength:100',
244 + ],
158 245 'variants.other_info.package_slug' => 'nullable|sanitizeText|maxLength:100',
159 246 'variants.other_info.weight' => 'nullable|numeric',
160 247 'variants.other_info.weight_unit' => 'nullable|sanitizeText|maxLength:10',
161 248 'variants.other_info.length' => 'nullable|numeric',
@@ -204,18 +291,13 @@
204 291 'variants.sku.unique' => esc_html__('The SKU must be unique.', 'fluent-cart'),
205 292 'variants.item_price.required' => esc_html__('Price is required.', 'fluent-cart'),
206 293 'variants.item_price.numeric' => esc_html__('Price must be a number.', 'fluent-cart'),
207 294 'variants.item_price.min' => esc_html__('Price must be a positive number greater than 0.', 'fluent-cart'),
208 - 'variants.stock_status.required_if' => esc_html__('Stock status is required.', 'fluent-cart'),
209 - 'variants.item_cost.required_if' => esc_html__('Item cost is required.', 'fluent-cart'),
210 295 'variants.fulfillment_type.required' => esc_html__('Fulfilment Type is required.', 'fluent-cart'),
211 296
212 297 'variants.other_info.description.max' => esc_html__('Description may not be greater than 255 characters.', 'fluent-cart'),
213 298 'variants.other_info.payment_type.required' => esc_html__('Payment Type is required.', 'fluent-cart'),
214 299 'variants.other_info.times.required_if' => esc_html__('Times is required.', 'fluent-cart'),
215 - 'variants.other_info.repeat_interval.required_if' => esc_html__('Interval is required.', 'fluent-cart'),
216 - 'variants.other_info.signup_fee.required_if' => esc_html__('Setup Fee Amount is required.', 'fluent-cart'),
217 - 'variants.other_info.signup_fee_name.required_if' => esc_html__('Setup Fee Name is required.', 'fluent-cart'),
218 300 'variants.other_info.trial_days.numeric' => esc_html__('Trial days must be a number.', 'fluent-cart'),
219 301 'variants.other_info.trial_days.max' => esc_html__('Trial period cannot exceed 365 days.', 'fluent-cart'),
220 302 ];
221 303 }