Skip to content

The issue tracked under #2139 has been addressed. #2222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: 2.1
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public function create(): View
*/
public function store(AttributeForm $request): RedirectResponse
{
$this->additionalValidation();

Event::dispatch('quote.create.before');

$quote = $this->quoteRepository->create($request->all());
Expand Down Expand Up @@ -94,6 +96,8 @@ public function edit(int $id): View
*/
public function update(AttributeForm $request, int $id): RedirectResponse
{
$this->additionalValidation();

Event::dispatch('quote.update.before', $id);

$quote = $this->quoteRepository->update($request->all(), $id);
Expand Down Expand Up @@ -187,4 +191,21 @@ public function print($id): Response|StreamedResponse
'Quote_'.$quote->subject.'_'.$quote->created_at->format('d-m-Y')
);
}

/**
* Additional validation for quote product items.
*/
private function additionalValidation(): void
{
$this->validate(request(), [
'items' => 'required|array',
'items.*.product_id' => 'required|exists:products,id',
'items.*.quantity' => 'required|numeric|min:0',
'items.*.price' => 'required|numeric|min:0',
'items.*.total' => 'required|numeric|min:0',
'items.*.discount_amount' => 'required|numeric|min:0',
'items.*.tax_amount' => 'required|numeric|min:0',
'items.*.final_total' => 'required|numeric|min:0',
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
$value = \Carbon\Carbon::parse($value)->format('Y-m-d');
}
}

$value = old($attribute->code, $value);
@endphp

<x-admin::form.control-group.control
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,13 @@ class="control"
::name="`${inputName}[product_id]`"
:placeholder="trans('admin::app.quotes.create.search-products')"
@on-selected="(product) => addProduct(product)"
rules="required"
:label="trans('admin::app.quotes.create.product-name')"
::class="errors[`${inputName}[product_id]`] ? 'border !border-red-600 hover:border-red-600' : ''"
/>

<x-admin::form.control-group.error name="items.item_0.product_id"/>
<x-admin::form.control-group.error name="items[item_0][product_id]"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -447,13 +453,15 @@ class="control"
type="inline"
::name="`${inputName}[quantity]`"
::value="product.quantity"
rules="required|decimal:4"
rules="required|numeric|min:1"
::errors="errors"
:label="trans('admin::app.quotes.create.quantity')"
:placeholder="trans('admin::app.quotes.create.quantity')"
@on-change="(event) => product.quantity = event.value"
position="center"
/>

<x-admin::form.control-group.error name="items.item_0.quantity"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -472,6 +480,8 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.price)"
/>

<x-admin::form.control-group.error name="items.item_0.price"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -490,6 +500,8 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.price * product.quantity)"
/>

<x-admin::form.control-group.error name="items.item_0.total"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -508,6 +520,8 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.discount_amount)"
/>

<x-admin::form.control-group.error name="items.item_0.discount_amount"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -526,6 +540,8 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.tax_amount)"
/>

<x-admin::form.control-group.error name="items.item_0.tax_amount"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -541,6 +557,8 @@ class="control"
position="center"
::value-label="$admin.formatPrice(parseFloat(product.price * product.quantity) + parseFloat(product.tax_amount) - parseFloat(product.discount_amount))"
/>

<x-admin::form.control-group.error name="items.item_0.final_total"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand Down
26 changes: 23 additions & 3 deletions packages/Webkul/Admin/src/Resources/views/quotes/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ class="!px-2 ltr:text-right rtl:text-left"
</template>
</x-admin::table.tbody>
</x-admin::table>

<x-admin::form.control-group.error name="items"/>
</div>

<!-- Add New Quote Item -->
Expand Down Expand Up @@ -425,7 +427,13 @@ class="control"
::value="{ id: product.product_id, name: product.name }"
@on-selected="(product) => addProduct(product)"
:placeholder="trans('admin::app.quotes.edit.search-products')"
rules="required"
:label="trans('admin::app.quotes.edit.product-name')"
::class="errors[`${inputName}[product_id]`] ? 'border !border-red-600 hover:border-red-600' : ''"
/>

<x-admin::form.control-group.error name="`items.${product.id}.product_id`"/>
<x-admin::form.control-group.error ::name="`${inputName}[product_id]`"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -443,6 +451,9 @@ class="control"
@on-change="(event) => product.quantity = event.value"
position="center"
/>


<x-admin::form.control-group.error ::name="`items.${product.id}.quantity`"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -452,7 +463,7 @@ class="control"
<x-admin::form.control-group.control
type="inline"
::name="`${inputName}[price]`"
::value="product.price"
::value="(product.price) ?? 0"
rules="required|decimal:4"
::errors="errors"
:label="trans('admin::app.quotes.create.price')"
Expand All @@ -461,6 +472,9 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.price)"
/>

<x-admin::form.control-group.error name="`items.${product.id}.price`"/>
<x-admin::form.control-group.error ::name="`${inputName}[price]`"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -470,7 +484,7 @@ class="control"
<x-admin::form.control-group.control
type="inline"
::name="`${inputName}[total]`"
::value="product.price * product.quantity"
::value="(product.price * product.quantity) ?? 0"
rules="required|decimal:4"
::errors="errors"
:label="trans('admin::app.quotes.create.total')"
Expand All @@ -479,6 +493,9 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.price * product.quantity)"
/>

<x-admin::form.control-group.error name="`items.${product.id}.total`"/>
<x-admin::form.control-group.error ::name="`${inputName}[total]`"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand All @@ -497,6 +514,9 @@ class="control"
position="center"
::value-label="$admin.formatPrice(product.discount_amount)"
/>

<x-admin::form.control-group.error name="`items.${product.id}.discount_amount`"/>
<x-admin::form.control-group.error ::name="`${inputName}[discount_amount]`"/>
</x-admin::form.control-group>
</x-admin::table.td>

Expand Down Expand Up @@ -768,7 +788,7 @@ class="icon-delete cursor-pointer text-2xl"
addProduct(result) {
this.product.product_id = result.id;
this.product.name = result.name;
this.product.price = result.price;
this.product.price = result.price ?? 0;
this.product.quantity = result.quantity ?? 1;
this.product.discount_amount = 0;
this.product.tax_amount = 0;
Expand Down
18 changes: 15 additions & 3 deletions packages/Webkul/Admin/tests/e2e-pw/tests/quotes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
createPerson,
generateDate,
generateName,
createProduct,
} from "../utils/faker";

test.describe("quotes management", () => {
Expand All @@ -12,7 +13,10 @@ test.describe("quotes management", () => {
* Create person.
*/
await adminPage.goto("admin/contacts/persons");
const Person = await createPerson(adminPage);
const person = await createPerson(adminPage);

await adminPage.goto("admin/products");
const product = await createProduct(adminPage);

/**
* Create quote.
Expand All @@ -36,10 +40,10 @@ test.describe("quotes management", () => {
await adminPage.getByRole("textbox", { name: "Search..." }).click();
await adminPage
.getByRole("textbox", { name: "Search..." })
.fill(Person.Name);
.fill(person.Name);
await adminPage
.getByRole("listitem")
.filter({ hasText: Person.Name })
.filter({ hasText: person.Name })
.click();

/**
Expand Down Expand Up @@ -97,6 +101,14 @@ test.describe("quotes management", () => {
await adminPage
.locator('input[name="shipping_address\\[postcode\\]"]')
.fill("201301");

await adminPage.locator('.relative.flex.cursor-pointer.items-center.justify-between.rounded.border.p-2').first().click();

await adminPage.getByRole("textbox", { name: "Search..." }).click();
await adminPage.getByRole("textbox", { name: "Search..." }).fill(product.name);

await adminPage.getByRole("listitem").filter({ hasText: product.name }).click();

await adminPage.getByRole("button", { name: "Save Quote" }).click();
await expect(adminPage.locator("#app")).toContainText("Success");
});
Expand Down
64 changes: 52 additions & 12 deletions packages/Webkul/Admin/tests/e2e-pw/utils/faker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ const usedSlugs = new Set();
*/
function generateName() {
const adjectives = [
"Cool", "Smart", "Fast", "Sleek", "Innovative", "Shiny", "Bold",
"Elegant", "Epic", "Mystic", "Brilliant", "Luminous", "Radiant",
"Majestic", "Vivid", "Glowing", "Dynamic", "Fearless", "Silent",
"Cool", "Smart", "Fast", "Sleek", "Innovative", "Shiny", "Bold",
"Elegant", "Epic", "Mystic", "Brilliant", "Luminous", "Radiant",
"Majestic", "Vivid", "Glowing", "Dynamic", "Fearless", "Silent",
"Electric", "Golden", "Blazing", "Timeless", "Noble", "Eternal"
];

const nouns = [
"Star", "Vision", "Echo", "Spark", "Horizon", "Nova", "Shadow",
"Wave", "Pulse", "Vortex", "Zenith", "Element", "Flare", "Comet",
"Galaxy", "Ember", "Crystal", "Sky", "Stone", "Blaze", "Eclipse",
"Star", "Vision", "Echo", "Spark", "Horizon", "Nova", "Shadow",
"Wave", "Pulse", "Vortex", "Zenith", "Element", "Flare", "Comet",
"Galaxy", "Ember", "Crystal", "Sky", "Stone", "Blaze", "Eclipse",
"Storm", "Orbit", "Phantom", "Mirage"
];

Expand Down Expand Up @@ -361,6 +361,24 @@ function generateCompanyName() {
return `${prefixes[Math.floor(Math.random() * prefixes.length)]} ${suffixes[Math.floor(Math.random() * suffixes.length)]}`;
}

function generateProductName() {
const adjectives = ['Awesome', 'Portable', 'Eco', 'Smart', 'Compact'];
const items = ['Phone', 'Laptop', 'Bottle', 'Bag', 'Watch'];
return (
adjectives[Math.floor(Math.random() * adjectives.length)] +
' ' +
items[Math.floor(Math.random() * items.length)]
);
}

function generatePrice() {
return (Math.random() * (999 - 10) + 10).toFixed(2);
}

function generateQuantity() {
return Math.floor(Math.random() * 100 + 1).toString();
}

/**
* Function to automate organization creation
*/
Expand All @@ -383,14 +401,14 @@ async function createOrganization(page) {
await page.getByRole('textbox', { name: 'City' }).fill('Delhi');
await page.getByRole('textbox', { name: 'Postcode' }).fill('123456');

/**
/**
* Click to add extra details
*/
await page.locator('div').filter({ hasText: /^Click to add$/ }).nth(2).click();
await page.getByRole('textbox', { name: 'Search...' }).fill('exampl');
await page.getByRole('listitem').filter({ hasText: 'Example' }).click();

/**
/**
* Click on "Save Organization"
*/
await page.getByRole('button', { name: 'Save Organization' }).click();
Expand Down Expand Up @@ -438,14 +456,35 @@ async function createPerson(page) {

return { Name, email, phone };
}

async function createProduct(page) {
const name = generateProductName();
const description = generateDescription();
const sku = generateSKU();
const price = generatePrice();
const quantity = generateQuantity();

await page.getByRole('link', { name: 'Create Product' }).click();

await page.getByRole('textbox', { name: 'Name *' }).fill(name);
await page.getByRole('textbox', { name: 'Description' }).fill(description);
await page.getByRole('textbox', { name: 'SKU *' }).fill(sku);
await page.getByRole('textbox', { name: 'Price *' }).fill(price);
await page.getByRole('textbox', { name: 'Quantity *' }).fill(quantity);

await page.getByRole('button', { name: 'Save Products' }).click();

return { name };
}

function getRandomDateTime() {
const year = Math.floor(Math.random() * (2030 - 2020 + 1)) + 2020;
const month = String(Math.floor(Math.random() * 12) + 1).padStart(2, '0');
const day = String(Math.floor(Math.random() * 28) + 1).padStart(2, '0');
const hours = String(Math.floor(Math.random() * 24)).padStart(2, '0');
const minutes = String(Math.floor(Math.random() * 60)).padStart(2, '0');
const seconds = String(Math.floor(Math.random() * 60)).padStart(2, '0');

return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

Expand All @@ -467,5 +506,6 @@ export {
createOrganization,
generateCompanyName,
createPerson,
getRandomDateTime
};
getRandomDateTime,
createProduct
};
Loading