diff --git a/.github/helper/install.sh b/.github/helper/install.sh index 21bb9d9a..9cec55c7 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -11,6 +11,7 @@ cd ./frappe-bench || exit bench -v setup requirements echo "Setting Up LMS App..." +bench get-app "https://github.com/frappe/payments" bench get-app lms "${GITHUB_WORKSPACE}" echo "Setting Up Sites & Database..." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfe2b8b4..66d9b00a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,9 @@ jobs: mkdir -p ~/bench-cache (cd && tar czf ~/bench-cache/bench.tgz frappe-bench) fi + - name: add payments app to bench + working-directory: /home/runner/frappe-bench + run: bench get-app https://github.com/frappe/payments - name: add lms app to bench working-directory: /home/runner/frappe-bench run: bench get-app lms $GITHUB_WORKSPACE diff --git a/cypress/e2e/course_creation.cy.js b/cypress/e2e/course_creation.cy.js index b5f5ae73..8a8e0f2d 100644 --- a/cypress/e2e/course_creation.cy.js +++ b/cypress/e2e/course_creation.cy.js @@ -21,10 +21,17 @@ describe("Course Creation", () => { "Test Course Description. I need a very big description to test the UI. This is a very big description. It contains more than once sentence. Its meant to be this long as this is a UI test. Its unbearably long and I'm not sure why I'm typing this much. I'm just going to keep typing until I feel like its long enough. I think its long enough now. I'm going to stop typing now." ); - cy.fixture("profile.png", "base64").then((fileContent) => { + cy.contains("Course Image") + .should("exist") + .parent() + .find('input[type="file"]') + .attachFile("profile.png", { force: true }); + + /* cy.fixture("profile.png", "base64").then((fileContent) => { + expect(fileContent).to.exist; cy.get("div") .contains("Course Image") - .siblings("div") + .parent() .children('input[type="file"]') .attachFile({ fileContent, @@ -32,7 +39,7 @@ describe("Course Creation", () => { mimeType: "image/png", encoding: "base64", }); - }); + }); */ /* Instructor */ cy.get("label") @@ -74,10 +81,10 @@ describe("Course Creation", () => { cy.button("Save").click(); // Add Chapter - cy.wait(1000); + cy.wait(500); cy.button("Add").click(); - cy.wait(1000); + cy.wait(500); cy.get("[data-dismissable-layer]") .should("be.visible") .within(() => { @@ -86,12 +93,10 @@ describe("Course Creation", () => { }); // Add Lesson - cy.wait(1000); + cy.wait(500); cy.button("Add Lesson").click(); - cy.wait(1000); + cy.wait(500); cy.url().should("include", "/learn/1-1/edit"); - cy.wait(1000); - cy.get("label").contains("Title").type("Test Lesson"); cy.get("#content .ce-block").type( "{enter}This is an extremely big paragraph that is meant to test the UI. This is a very long paragraph. It contains more than once sentence. Its meant to be this long as this is a UI test. Its unbearably long and I'm not sure why I'm typing this much. I'm just going to keep typing until I feel like its long enough. I think its long enough now. I'm going to stop typing now." @@ -99,21 +104,23 @@ describe("Course Creation", () => { cy.button("Save").click(); // View Course - cy.wait(1000); + cy.wait(500); cy.visit("/lms/courses"); cy.closeOnboardingModal(); cy.url().should("include", "/lms/courses"); - cy.get(".grid a:first").within(() => { - cy.get("div").contains("Test Course"); - cy.get("div").contains( - "Test Course Short Introduction to test the UI" - ); - cy.get(".bg-cover") - .invoke("css", "background-image") - .should("include", "/files/profile"); - }); - cy.get(".grid a:first").click(); + cy.get("div") + .contains("Test Course") + .closest("a") + .within(() => { + cy.get("div").contains( + "Test Course Short Introduction to test the UI" + ); + cy.get(".bg-cover") + .invoke("css", "background-image") + .should("include", "/files/profile"); + }); + cy.get("div").contains("Test Course").closest("a").click(); cy.url().should("include", "/lms/courses/test-course"); cy.get("div").contains("Test Course"); cy.get("div").contains("Test Course Short Introduction to test the UI"); @@ -131,7 +138,7 @@ describe("Course Creation", () => { cy.get("[id^=headlessui-disclosure-panel-").within(() => { cy.get("div").contains("Test Lesson").click(); }); - cy.wait(3000); + cy.wait(500); // View Lesson cy.url().should("include", "/learn/1-1"); @@ -142,7 +149,6 @@ describe("Course Creation", () => { ); // Add Discussion - cy.get("span").contains("Community").click(); cy.button("New Question").click(); cy.wait(500); cy.get("[data-dismissable-layer]").within(() => { @@ -165,5 +171,16 @@ describe("Course Creation", () => { cy.get("div").contains( "This is a test comment. This will check if the UI is working properly." ); + + // Delete Course + cy.get("div").contains("Test Course").click(); + cy.get("button").contains("Settings").click(); + cy.get("header").within(() => { + cy.get("svg.lucide.lucide-trash2-icon").click(); + }); + cy.get("span").contains("Delete").click(); + cy.wait(500); + cy.url().should("include", "/lms/courses"); + cy.get("div").contains("Test Course").should("not.exist"); }); }); diff --git a/frontend/package.json b/frontend/package.json index d838d5e2..d94a0be5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,8 +27,6 @@ "@editorjs/table": "2.4.2", "@vueuse/core": "^14.1.0", "ace-builds": "1.36.2", - "apexcharts": "4.3.0", - "chart.js": "4.4.1", "codemirror": "6.0.1", "dayjs": "1.11.10", "dompurify": "3.2.6", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 697aa346..25f6d8de 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,6 +1,6 @@ -
+
@@ -90,17 +93,18 @@ :label="__('Currency')" v-model="transactionData.currency" doctype="Currency" - :required="true" + :required="!!fieldMeta.currency?.reqd" />
@@ -113,21 +117,25 @@ v-if="transactionData.coupon" :label="__('Coupon Code')" v-model="transactionData.coupon" + :required="!!fieldMeta.coupon?.reqd" /> @@ -140,17 +148,27 @@ :label="__('Address')" v-model="transactionData.address" doctype="Address" - :required="true" + :required="!!fieldMeta.address?.reqd" + /> + + - - @@ -171,6 +189,10 @@ const show = defineModel('show') const props = defineProps<{ transactions: any data: any + fieldMeta: Record< + string, + { reqd?: number; default?: string; description?: string } + > }>() const saveTransaction = () => { @@ -211,48 +233,49 @@ const updateTransaction = () => { } const openDetails = () => { - if (props.data) { - const docType = props.data.payment_for_document_type - const docName = props.data.payment_for_document - if (docType && docName) { - router.push({ - name: docType == 'LMS Course' ? 'CourseDetail' : 'BatchDetail', - params: { - [docType == 'LMS Course' ? 'courseName' : 'batchName']: docName, - }, - }) - } + const docType = transactionData.value?.payment_for_document_type + const docName = transactionData.value?.payment_for_document + if (docType && docName) { + router.push({ + name: docType == 'LMS Course' ? 'CourseDetail' : 'BatchDetail', + params: { + [docType == 'LMS Course' ? 'courseName' : 'batchName']: docName, + }, + }) show.value = false } } -const emptyTransactionData = { +const getDefault = (fieldname: string) => + props.fieldMeta[fieldname]?.default || null + +const getEmptyTransactionData = () => ({ payment_received: false, payment_for_certificate: false, - member: null, - billing_name: null, - source: null, - payment_for_document_type: null, - payment_for_document: null, + member: getDefault('member'), + billing_name: getDefault('billing_name'), + source: getDefault('source'), + payment_for_document_type: getDefault('payment_for_document_type'), + payment_for_document: getDefault('payment_for_document'), member_consent: false, - currency: null, - amount: null, - amount_with_gst: null, - coupon: null, - coupon_code: null, - discount_amount: null, - original_amount: null, - order_id: null, - payment_id: null, - gstin: null, - pan: null, - address: null, -} + currency: getDefault('currency'), + amount: getDefault('amount'), + amount_with_gst: getDefault('amount_with_gst'), + coupon: getDefault('coupon'), + coupon_code: getDefault('coupon_code'), + discount_amount: getDefault('discount_amount'), + original_amount: getDefault('original_amount'), + order_id: getDefault('order_id'), + payment_id: getDefault('payment_id'), + gstin: getDefault('gstin'), + pan: getDefault('pan'), + address: getDefault('address'), +}) watch( () => props.data, (newVal) => { - transactionData.value = newVal ? { ...newVal } : emptyTransactionData + transactionData.value = newVal ? { ...newVal } : getEmptyTransactionData() }, { immediate: true } ) diff --git a/frontend/src/components/Settings/Transactions/Transactions.vue b/frontend/src/components/Settings/Transactions/Transactions.vue index d2045b8a..eeb0d2a5 100644 --- a/frontend/src/components/Settings/Transactions/Transactions.vue +++ b/frontend/src/components/Settings/Transactions/Transactions.vue @@ -3,6 +3,7 @@ v-if="step == 'new'" :transactions="transactions" :data="data" + :fieldMeta="fieldMeta.data || {}" v-model:show="show" @updateStep="updateStep" /> @@ -17,13 +18,14 @@ v-else-if="step == 'details'" :transactions="transactions" :data="data" + :fieldMeta="fieldMeta.data || {}" v-model:show="show" @updateStep="updateStep" /> diff --git a/frontend/src/pages/Batches/BatchDetail.vue b/frontend/src/pages/Batches/BatchDetail.vue index 6803f5ca..c90f80da 100644 --- a/frontend/src/pages/Batches/BatchDetail.vue +++ b/frontend/src/pages/Batches/BatchDetail.vue @@ -18,7 +18,7 @@ { } const batchMenu = computed(() => { + if (!batch.data?.certification && !canMakeAnnouncement()) { + return [] + } let options = [ { label: __('Generate Certificates'), diff --git a/frontend/src/pages/Batches/components/BatchOverlay.vue b/frontend/src/pages/Batches/components/BatchOverlay.vue index d7b88e00..73777cee 100644 --- a/frontend/src/pages/Batches/components/BatchOverlay.vue +++ b/frontend/src/pages/Batches/components/BatchOverlay.vue @@ -56,7 +56,7 @@ -
+
-