import job from "../../fixtures/jobs/job-3.json"; import job2 from "../../fixtures/jobs/job-4.json"; import moment from "moment"; import Dinero from "dinero.js"; const uuid = () => Cypress._.random(0, 1e6); describe.only( "Billing job parts orders", { defaultCommandTimeout: 10000, }, () => { const today = moment(new Date()).format("YYYY-MM-DD"); beforeEach(() => { cy.viewport(1280, 720); cy.visit("/manage/jobs"); cy.intercept("POST", Cypress.env("graphql_dev_endpoint"), (req) => { if (req.body.operationName === "SEARCH_VENDOR_AUTOCOMPLETE") { req.alias = "vendors"; } }); cy.get('[data-cy="active-jobs-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("active-jobs-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@active-jobs-table") .contains(job.clm_no) .first() .parent() .find('[data-cy="active-job-link"]') .click(); }); it("receives a part bill", () => { // Order a part // Go to repair data tab cy.get('[data-cy="tab-repairdata"]').should("be.visible").click(); // Click on filter parts only cy.get('[data-cy="filter-parts-button"]') .should("not.be.disabled") .click(); // Select multiple rows cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-checkbox-input") .click(); // Click Order Parts cy.get('[data-cy="order-parts-button"]') .should("not.be.disabled") .click(); // Modal should be visible cy.get('[data-cy="parts-order-modal"]').should("be.visible"); // Fill required fields cy.get(".ant-select-selection-search").find(`#vendorid`).click(); cy.get(`#vendorid_list`) .next() .find(".ant-select-item-option-content") .first() .click({ force: true }); cy.get("#deliver_by").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="part-order-comments"]').type("testing from cypress"); cy.get('[data-cy="part-order-select-none"]').check(); cy.get('[data-cy="order-part-submit"]').should("not.be.disabled").click(); cy.get(".ant-notification-notice-message").contains( "Parts order created successfully." ); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-table-cell") .eq(15) .contains("Ordered"); cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); // Find the first row in the parts order cy.get('[data-cy="part-orders-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("orders-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@orders-table") .first() .should("be.visible") .find('[data-cy="receive-bill-button"]') .click(); // fill out form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-form-parts-bin"]').find("input").click(); cy.get("#location_list") .next() .find(".ant-select-item-option-content") .first() .click(); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { const totals = cells.toArray().map((el) => Number(el.value)); const sum = Cypress._.sum(totals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); }); // Click save cy.get('[data-cy="bill-form-save-button"]').click(); cy.get(".ant-notification-notice-message").contains( "Invoice added successfully." ); cy.get('[data-cy="tab-repairdata"]').should("be.visible").click(); cy.get('[data-cy="filter-parts-button"]') .should("not.be.disabled") .click(); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-table-cell") .eq(15) .contains("Received"); }); it("backorders part from order", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="part-orders-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("orders-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@orders-table") .first() .should("be.visible") .find('[data-cy="view-part-order-button"]') .click(); cy.get('[data-cy="mark-backorder-button"]').click(); cy.get(".backorder-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="mark-for-backorder-button"]').click(); cy.get(".ant-drawer-close").click(); cy.get('[data-cy="tab-repairdata"]').should("be.visible").click(); cy.get('[data-cy="filter-parts-button"]') .should("not.be.disabled") .click(); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-table-cell") .eq(15) .contains("Backordered"); }); it.only("order parts inhouse", () => { cy.get('[data-cy="tab-repairdata"]').should("be.visible").click(); // Click on filter parts only cy.get('[data-cy="filter-parts-button"]') .should("not.be.disabled") .click(); // Select multiple rows cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-checkbox-input") .click(); // Click Order Parts cy.get('[data-cy="order-parts-inhouse-button"]') .should("not.be.disabled") .click(); cy.antdSelect("bill-vendor"); cy.antdSelect("bill-cost-center"); cy.get('[data-cy="bill-form-save-button"]').click({ force: true }); cy.get(".ant-notification-notice-message").contains( "Invoice added successfully." ); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find(".ant-table-cell") .eq(15) .contains("Received"); }); it("posts bill directly", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="bills-post-button"]').should("be.visible").click(); // Add New Line cy.get('[data-cy="bill-line-add-button"]') .should("not.be.disabled") .click(); // Select Vendor cy.antdSelect("bill-vendor"); // Select Line cy.antdSelect("bill-line", "-- Not On Estimate --"); // Fill the Form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-form-parts-bin"]').find("input").click(); cy.get("#location_list") .next() .find(".ant-select-item-option-content") .first() .click(); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { const totals = cells.toArray().map((el) => Number(el.value)); const sum = Cypress._.sum(totals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); }); cy.antdSelect("bill-cost-center"); // Click save cy.get('[data-cy="bill-form-save-button"]').click(); cy.get(".ant-notification-notice-message").contains( "Invoice added successfully." ); }); it("posts a bill with save and new", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="bills-post-button"]').should("be.visible").click(); // Add New Line cy.get('[data-cy="bill-line-add-button"]') .should("not.be.disabled") .click(); // Select Vendor cy.antdSelect("bill-vendor"); // Select Line cy.antdSelect("bill-line", "-- Not On Estimate --"); // Fill the Form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-form-parts-bin"]').find("input").click(); cy.get("#location_list") .next() .find(".ant-select-item-option-content") .first() .click(); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { const totals = cells.toArray().map((el) => Number(el.value)); const sum = Cypress._.sum(totals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); }); cy.antdSelect("bill-cost-center"); // Click save cy.get('[data-cy="bill-form-savenew-button"]') .should("not.be.disabled") .click(); cy.get(".ant-notification-notice-message").contains( "Invoice added successfully." ); }); it("uploads a document to a bill", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="bills-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("bills-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@bills-table") .first() .should("be.visible") .find('[data-cy="edit-bill-button"]') .click(); cy.location("search").should("include", "billid"); cy.get('[data-cy="bill-edit-form"]') .find(".ant-upload #bill-document-upload") .selectFile("job.json", { force: true }); }); it("marks bill as exported", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="bills-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("bills-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@bills-table") .find('[data-cy="bill-exported-checkbox"]') .not(":checked") .first() .as("export-status") .parent() .parent() .parent() .parent() .find('[data-cy="edit-bill-button"]') .click(); cy.location("search").should("include", "billid"); cy.get('[data-cy="bill-mark-export-button"]') .as("mark-for-export") .click(); cy.get("@mark-for-export").should("be.disabled"); }); it("marks bill for re-export", () => { cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); cy.get('[data-cy="bills-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("bills-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@bills-table") .find('[data-cy="bill-exported-checkbox"]') .filter(":checked") .first() .as("export-status") .parent() .parent() .parent() .parent() .find('[data-cy="edit-bill-button"]') .click(); cy.location("search").should("include", "billid"); cy.get('[data-cy="bill-mark-reexport-button"]') .as("mark-for-reexport") .click(); cy.get("@mark-for-reexport").should("be.disabled"); }); } ); describe( "Validating and calculating bills", { defaultCommandTimeout: 10000, }, () => { const today = moment(new Date()).format("YYYY-MM-DD"); const jobLines = job2.joblines.data.filter( (line) => line.part_type === "PAS" || line.part_type === "PAE" ); const linesTotal = jobLines.reduce( (prev, line) => prev + line.act_price, 0 ); beforeEach(() => { cy.viewport(1280, 720); cy.visit("/manage/jobs"); cy.intercept("POST", Cypress.env("graphql_dev_endpoint"), (req) => { if (req.body.operationName === "SEARCH_VENDOR_AUTOCOMPLETE") { req.alias = "vendors"; } }); cy.get('[data-cy="active-jobs-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("active-jobs-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@active-jobs-table") .contains(job2.clm_no) .first() .parent() .find('[data-cy="active-job-link"]') .click(); // Go to repair data tab cy.get('[data-cy="tab-partssublet"]').should("be.visible").click(); }); it("validates auto reconciliation through posting bill", () => { // Find the first row in the parts order cy.get('[data-cy="part-orders-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("orders-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@orders-table") .first() .should("be.visible") .find('[data-cy="receive-bill-button"]') .click(); // fill out form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-form-parts-bin"]').find("input").click(); cy.get("#location_list") .next() .find(".ant-select-item-option-content") .first() .click(); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .as("retailPrice") .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { const totals = cells.toArray().map((el) => Number(el.value)); const sum = Cypress._.sum(totals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); // Get taxes add it to the sum cy.get('[data-cy="bill-form-tax"]').then((taxes) => { const subtotals = taxes .toArray() .map((el) => Number(el.innerText.substring(1))); const totalTax = Cypress._.sum(subtotals); const billAmount = sum + totalTax; cy.get('[data-cy="bill-form-bill-total"]') .find("input") .clear() .type(billAmount); }); }); cy.get("#bill-form-discrepancy").should("have.text", "$0.00"); // Click save cy.get('[data-cy="bill-form-save-button"]').click(); cy.get("@retailPrice") .invoke("val") .then((val) => { const discrepancy = linesTotal - Number(val); cy.get("#retailtotal").should("have.text", `$${val}`); cy.get(".discrepancy").each(($statistic) => { cy.wrap($statistic).should( "have.text", Dinero({ amount: discrepancy, precision: 0, }).toFormat() ); }); }); }); it("returning item and validating statistics", () => { cy.get('[data-cy="bills-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("bills-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@bills-table") .find('[data-cy="credit-memo-checkbox"]') .filter(":not(:checked)") .first() .should("not.be.disabled") .parent() .parent() .parent() .parent() .find('[data-cy="return-items-button"]') .click(); cy.get('[data-cy="billline-checkbox"]').check(); cy.get('[data-cy="billline-return-items-ok-button"]').click(); cy.get('[data-cy="billline-actual-price"]') .find(".ant-form-item-control-input-content") .then((prices) => { const totals = prices .toArray() .map((el) => Number(el.innerText.substring(1))); const sum = Cypress._.sum(totals); const price = Dinero({ amount: sum * 100, }).toFormat(); cy.get('[data-cy="order-quantity"]').each((input) => { cy.wrap(input).type("1"); }); cy.get('[data-cy="part-order-select-none"]').click(); cy.get('[data-cy="order-part-submit"]').click(); cy.get("#totalReturns").should("have.text", price); cy.get("#calculatedcreditsnotreceived").should("have.text", price); cy.get("#creditsnotreceived").should("have.text", price); }); }); it("receives credit memo without return part", () => { // Find the first row in the parts order cy.get('[data-cy="part-orders-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("orders-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@orders-table") .find('[data-cy="part-order-return-checkbox"]') .filter(":checked") .first() .parent() .parent() .parent() .parent() .find('[data-cy="receive-bill-button"]') .click(); // fill out form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="is-credit-memo-switch"]').click(); cy.get('[data-cy="is-credit-memo-switch"]').should( "have.attr", "aria-checked", "false" ); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { cy.get('[data-cy="bill-line-actual-price"]').then((priceCells) => { const totals = cells.toArray().map((el) => Number(el.value)); const priceTotals = priceCells .toArray() .map((el) => Number(el.value)); const sum = Cypress._.sum(totals); const priceSum = Cypress._.sum(priceTotals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); // Get taxes add it to the sum cy.get('[data-cy="bill-form-tax"]').then((taxes) => { const subtotals = taxes .toArray() .map((el) => Number(el.innerText.substring(1))); const totalTax = Cypress._.sum(subtotals); const billAmount = sum + totalTax; cy.get('[data-cy="bill-form-bill-total"]') .find("input") .clear() .type(billAmount); }); cy.get("#bill-form-discrepancy").should("have.text", "$0.00"); cy.get(`.ant-select-bill-cost-center > .ant-select-selector`).each( (select) => { cy.wrap(select).click(); cy.wrap(select) .find("input") .invoke("attr", "id") .then((id) => { cy.get(`#${id}_list`) .next() .find(".ant-select-item-option-content") .first() .click({ force: true }); }); } ); cy.get('[data-cy="bill-form-save-button"]').click(); cy.get("#totalReturns") .invoke("text") .then((value) => { const totalReturns = Number(value.substring(1)) - priceSum < 0 ? 0 : Number(value.substring(1)) - priceSum; cy.get("#calculatedcreditsnotreceived").should( "have.text", Dinero({ amount: totalReturns, precision: 0, }).toFormat() ); }); }); }); }); it("receives credit memo with return part", () => { // Find the first row in the parts order cy.get('[data-cy="part-orders-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .as("orders-table") .should("not.have.class", "ant-table-placeholder"); cy.get("@orders-table") .find('[data-cy="part-order-return-checkbox"]') .filter(":checked") .first() .parent() .parent() .parent() .parent() .find('[data-cy="receive-bill-button"]') .click(); // fill out form cy.get('[data-cy="bill-form-invoice"]').type(uuid()); cy.get("#bill-form-date").click(); cy.get(`[title="${today}"]`).should("be.visible").click({ force: true }); cy.get('[data-cy="bill-line-table"]').each(($row) => { // get retail amount cy.wrap($row) .find('[data-cy="bill-line-actual-price"]') .click({ force: true, multiple: true }); cy.wrap($row) .find('[data-cy="bill-line-actual-cost"]') .click({ multiple: true }); }); cy.get('[data-cy="is-credit-memo-switch"]').should( "have.attr", "aria-checked", "true" ); cy.get('[data-cy="bill-line-actual-cost"]').then((cells) => { cy.get('[data-cy="bill-line-actual-price"]').then((priceCells) => { const totals = cells.toArray().map((el) => Number(el.value)); const priceTotals = priceCells .toArray() .map((el) => Number(el.value)); const sum = Cypress._.sum(totals); const priceSum = Cypress._.sum(priceTotals); cy.get('[data-cy="bill-form-bill-total"]').type(sum); // Get taxes add it to the sum cy.get('[data-cy="bill-form-tax"]').then((taxes) => { const subtotals = taxes .toArray() .map((el) => Number(el.innerText.substring(1))); const totalTax = Cypress._.sum(subtotals); const billAmount = sum + totalTax; cy.get('[data-cy="bill-form-bill-total"]') .find("input") .clear() .type(billAmount); }); cy.get("#bill-form-discrepancy").should("have.text", "$0.00"); cy.get(`.ant-select-bill-cost-center > .ant-select-selector`).each( (select) => { cy.wrap(select).click(); cy.wrap(select) .find("input") .invoke("attr", "id") .then((id) => { cy.get(`#${id}_list`) .next() .find(".ant-select-item-option-content") .first() .click({ force: true }); }); } ); cy.get('[data-cy="mark-as-received-checkbox"]').check({ multiple: true, }); cy.get('[data-cy="bill-form-save-button"]').click(); cy.get("#totalReturns") .invoke("text") .then((value) => { const totalReturns = Number(value.substring(1)) - priceSum < 0 ? 0 : Number(value.substring(1)) - priceSum; cy.get("#creditsnotreceived").should( "have.text", Dinero({ amount: totalReturns, precision: 0, }).toFormat() ); }); }); }); }); it("views the row expander if it has the order and bill", () => { cy.get('[data-cy="tab-repairdata"]').should("be.visible").click(); cy.get('[data-cy="filter-parts-button"]') .should("not.be.disabled") .click(); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find("td") .first() .click(); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find("td") .eq(13) .find("div") .should("exist"); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find("td") .eq(14) .find("div") .should("exist"); cy.get('[data-cy="repair-data-table"]') .find(".ant-table-tbody") .find("> tr:not(.ant-table-measure-row)") .first() .find("td") .eq(15) .find("div") .should("have.text", "Returned"); cy.get('[data-cy="parts-bills-order"]') .should("be.visible") .find("li") .first() .should("not.have.text", "This part has not yet been ordered."); }); } );