From 8729a0bb6bf69e866ca5922eff3f20b8dd7e7cd6 Mon Sep 17 00:00:00 2001 From: jabir-tridz Date: Mon, 6 Nov 2023 10:54:44 +0000 Subject: [PATCH] Initial Commit of URY Pulse App --- .github/workflows/ci.yml | 90 ++++ .gitignore | 7 + FEATURES.md | 50 ++ INSTALLATION.md | 42 ++ MANIFEST.in | 18 + README.md | 39 ++ SETUP.md | 37 ++ license.txt | 1 + requirements.txt | 1 + setup.py | 19 + ury_pulse/__init__.py | 3 + ury_pulse/config/__init__.py | 0 ury_pulse/config/desktop.py | 10 + ury_pulse/config/docs.py | 10 + ury_pulse/hooks.py | 217 +++++++++ ury_pulse/modules.txt | 1 + ury_pulse/patches.txt | 0 ury_pulse/public/.gitkeep | 0 ury_pulse/templates/__init__.py | 0 ury_pulse/templates/pages/__init__.py | 0 ury_pulse/ury_pulse/__init__.py | 0 ury_pulse/ury_pulse/doctype/__init__.py | 0 .../doctype/ury_cost_of_goods/__init__.py | 0 .../ury_cost_of_goods/ury_cost_of_goods.json | 84 ++++ .../ury_cost_of_goods/ury_cost_of_goods.py | 8 + .../doctype/ury_daily_p_and_l/__init__.py | 0 .../profit_loss_details.html | 129 +++++ .../test_ury_daily_p_and_l.py | 9 + .../ury_daily_p_and_l/ury_daily_p_and_l.js | 77 +++ .../ury_daily_p_and_l/ury_daily_p_and_l.json | 457 ++++++++++++++++++ .../ury_daily_p_and_l/ury_daily_p_and_l.py | 297 ++++++++++++ .../doctype/ury_fixed_expenses/__init__.py | 0 .../ury_fixed_expenses.json | 41 ++ .../ury_fixed_expenses/ury_fixed_expenses.py | 8 + .../doctype/ury_materials/__init__.py | 0 .../doctype/ury_materials/ury_materials.json | 41 ++ .../doctype/ury_materials/ury_materials.py | 8 + .../doctype/ury_p_and_l_breakup/__init__.py | 0 .../ury_p_and_l_breakup.json | 51 ++ .../ury_p_and_l_breakup.py | 8 + .../doctype/ury_p_and_l_materials/__init__.py | 0 .../ury_p_and_l_materials.json | 63 +++ .../ury_p_and_l_materials.py | 8 + .../doctype/ury_report_settings/__init__.py | 0 .../test_ury_report_settings.py | 9 + .../ury_report_settings.js | 27 ++ .../ury_report_settings.json | 188 +++++++ .../ury_report_settings.py | 8 + .../doctype/ury_variable_expenses/__init__.py | 0 .../ury_variable_expenses.json | 51 ++ .../ury_variable_expenses.py | 8 + ury_pulse/ury_pulse/report/__init__.py | 0 .../report/average_bill_value/__init__.py | 0 .../average_bill_value.json | 56 +++ .../report/cancelled_invoices/__init__.py | 0 .../cancelled_invoices.json | 56 +++ .../report/customer_data/__init__.py | 0 .../report/customer_data/customer_data.json | 64 +++ .../report/daywise_invoices/__init__.py | 0 .../daywise_invoices/daywise_invoices.json | 56 +++ .../report/daywise_sales/__init__.py | 0 .../report/daywise_sales/daywise_sales.json | 56 +++ .../report/employee_sales/__init__.py | 0 .../report/employee_sales/employee_sales.json | 56 +++ .../report/item_wise_sales/__init__.py | 0 .../item_wise_sales/item_wise_sales.json | 58 +++ .../report/month_wise_sales/__init__.py | 0 .../month_wise_sales/month_wise_sales.json | 43 ++ .../report/repeated_customers/__init__.py | 0 .../repeated_customers.json | 56 +++ .../report/today's_sales/__init__.py | 0 .../report/today's_sales/today's_sales.json | 42 ++ ury_pulse/www/__init__.py | 0 73 files changed, 2668 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 FEATURES.md create mode 100644 INSTALLATION.md create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 SETUP.md create mode 100644 license.txt create mode 100644 requirements.txt create mode 100644 setup.py create mode 100644 ury_pulse/__init__.py create mode 100644 ury_pulse/config/__init__.py create mode 100644 ury_pulse/config/desktop.py create mode 100644 ury_pulse/config/docs.py create mode 100644 ury_pulse/hooks.py create mode 100644 ury_pulse/modules.txt create mode 100644 ury_pulse/patches.txt create mode 100644 ury_pulse/public/.gitkeep create mode 100644 ury_pulse/templates/__init__.py create mode 100644 ury_pulse/templates/pages/__init__.py create mode 100644 ury_pulse/ury_pulse/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_cost_of_goods/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/test_ury_daily_p_and_l.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.js create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_fixed_expenses/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_materials/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_report_settings/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_report_settings/test_ury_report_settings.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.js create mode 100644 ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_variable_expenses/__init__.py create mode 100644 ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.json create mode 100644 ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.py create mode 100644 ury_pulse/ury_pulse/report/__init__.py create mode 100644 ury_pulse/ury_pulse/report/average_bill_value/__init__.py create mode 100644 ury_pulse/ury_pulse/report/average_bill_value/average_bill_value.json create mode 100644 ury_pulse/ury_pulse/report/cancelled_invoices/__init__.py create mode 100644 ury_pulse/ury_pulse/report/cancelled_invoices/cancelled_invoices.json create mode 100644 ury_pulse/ury_pulse/report/customer_data/__init__.py create mode 100644 ury_pulse/ury_pulse/report/customer_data/customer_data.json create mode 100644 ury_pulse/ury_pulse/report/daywise_invoices/__init__.py create mode 100644 ury_pulse/ury_pulse/report/daywise_invoices/daywise_invoices.json create mode 100644 ury_pulse/ury_pulse/report/daywise_sales/__init__.py create mode 100644 ury_pulse/ury_pulse/report/daywise_sales/daywise_sales.json create mode 100644 ury_pulse/ury_pulse/report/employee_sales/__init__.py create mode 100644 ury_pulse/ury_pulse/report/employee_sales/employee_sales.json create mode 100644 ury_pulse/ury_pulse/report/item_wise_sales/__init__.py create mode 100644 ury_pulse/ury_pulse/report/item_wise_sales/item_wise_sales.json create mode 100644 ury_pulse/ury_pulse/report/month_wise_sales/__init__.py create mode 100644 ury_pulse/ury_pulse/report/month_wise_sales/month_wise_sales.json create mode 100644 ury_pulse/ury_pulse/report/repeated_customers/__init__.py create mode 100644 ury_pulse/ury_pulse/report/repeated_customers/repeated_customers.json create mode 100644 ury_pulse/ury_pulse/report/today's_sales/__init__.py create mode 100644 ury_pulse/ury_pulse/report/today's_sales/today's_sales.json create mode 100644 ury_pulse/www/__init__.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..26baf57 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,90 @@ + +name: CI + +on: + push: + branches: + - develop + pull_request: + +concurrency: + group: develop-ury_pulse-${{ github.event.number }} + cancel-in-progress: true + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + name: Server + + services: + mariadb: + image: mariadb:10.6 + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.10' + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: 14 + check-latest: true + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py', '**/setup.cfg') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: 'echo "::set-output name=dir::$(yarn cache dir)"' + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Setup + run: | + pip install frappe-bench + bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" + + - name: Install + working-directory: /home/runner/frappe-bench + run: | + bench get-app ury_pulse $GITHUB_WORKSPACE + bench setup requirements --dev + bench new-site --db-root-password root --admin-password admin test_site + bench --site test_site install-app ury_pulse + bench build + env: + CI: 'Yes' + + - name: Run Tests + working-directory: /home/runner/frappe-bench + run: | + bench --site test_site set-config allow_tests true + bench --site test_site run-tests --app ury_pulse + env: + TYPE: server diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63253c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +*.pyc +*.egg-info +*.swp +tags +ury_pulse/docs/current +node_modules/ \ No newline at end of file diff --git a/FEATURES.md b/FEATURES.md new file mode 100644 index 0000000..e592022 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1,50 @@ +## Features of URY Pulse + + +### Daily Profit and Loss: + +**The heart of URY Pulse is the Daily Profit and Loss report. Here's how it works:** + +- Buying Price List : + - Users can set the buying price list to calculate the cost of goods. + +- Direct Expenses : + - This section includes expenses such as consumables (burning materials), their cost per unit, and direct fixed expenses (daily fixed expenses). You can set expense names and amounts for items that are part of your daily operational costs. + +- Indirect Expenses : + - Indirect expenses consist of electricity costs per unit, expense names, and amounts that are also daily fixed expenses. Additionally, there's a section for percentage expenses, which allows you to store expense percentages based on either net sales or gross sales. You can also set depreciation in this section. + + +### Daily P and L Calculation: + +**Once you've set up the necessary data in the Daily Profit and Loss section of URY Report Settings, the system can calculate your daily profit and loss, including the following components:** + + - Gross Sales: The total sales for the day.. + - Direct Expenses: The sum of consumables and other direct fixed expenses. + - Cost of Goods Sold: This includes the cost of the items sold, factoring in product bundles and Bill of Materials (BOM) sub-items. +- Gross Profit/Loss: The difference between gross sales and the cost of goods sold. +- Indirect Expenses: The total of indirect fixed expenses and any percentage-based expenses. +- Net Profit/Loss: The final profit or loss for the day. + +**By inputting daily readings for consumables, electricity, and any other expenses, and then saving and submitting the document, you can generate a detailed daily profit and loss report, complete with a breakdown of the cost of goods sold. This report is an invaluable tool for restaurant owners and managers to track their financial performance on a daily basis.** + + +### Reports: + + **It offers a wide range of reports, including the following:** + +1. Today's Sales +2. Daywise Sales +3. Daywise Invoices +4. Month Wise Sales +5. Average Bill Value +6. Cancelled Invoices +7. Item Wise Sales +8. Customer Data +9. Repeated Customers +10. Employee Sales + + +### Customizable Branch Timings: + +- URY Pulse allows you to set varying branch timings in the URY Report settings, including extended hours. This feature ensures that your reports accurately reflect the operational hours of your restaurant. \ No newline at end of file diff --git a/INSTALLATION.md b/INSTALLATION.md new file mode 100644 index 0000000..0cc14bf --- /dev/null +++ b/INSTALLATION.md @@ -0,0 +1,42 @@ +# URY Pulse Installation + +**Prerequisite Setup:** +- Before using URY Pulse, ensure you have URY and Frappe HR installed. +- Follow the [URY installation guide](https://github.com/ury-erp/ury/blob/main/INSTALLATION.md) for the installation process. + +### To install URY Pulse, follow these steps: + +**Create New Site:** + +```sh + $ bench new-site sitename +``` +**Install the Frappe HR app to your bench:** + +```sh + $ $ bench get-app hrms +``` + +**Install the URY Pulse app to your bench:** + +```sh + $ bench get-app ury_pulse https://github.com/ury-erp/pulse.git +``` + +**To install Frappe HR into site:** + +```sh + $ bench --site sitename install-app hrms +``` + +**To install URY Pulse into site:** + +```sh + $ bench --site sitename install-app ury_pulse +``` + +**Migrate the site:** + +```sh + $ bench --site sitename migrate +``` \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..fecea14 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,18 @@ +include MANIFEST.in +include requirements.txt +include *.json +include *.md +include *.py +include *.txt +recursive-include ury_pulse *.css +recursive-include ury_pulse *.csv +recursive-include ury_pulse *.html +recursive-include ury_pulse *.ico +recursive-include ury_pulse *.js +recursive-include ury_pulse *.json +recursive-include ury_pulse *.md +recursive-include ury_pulse *.png +recursive-include ury_pulse *.py +recursive-include ury_pulse *.svg +recursive-include ury_pulse *.txt +recursive-exclude ury_pulse *.pyc \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..933a61c --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# URY Pulse - Reporting Tool For Restaurants + +URY Pulse is a powerful reporting tool designed to provide comprehensive insights and analytics for restaurants. It offers a range of reports, including Daily Profit and Loss (P&L), as well as various other essential data to help restaurant owners and managers make informed decisions. + +> :warning: Warning : +> URY Pulse is currently in active development. Not recommended for use in production unless you know what you are doing. + +> :information_source: Note : +> Our system has been successfully running at scale, serving over 10+ outlets for the past 10 months. + + - [Part of the URY Ecosystem](https://github.com/ury-erp/ury#readme) + + + +## Features + +below is the key Features of URY Pulse + +- Daily Profit and Loss +- Various Reports +- Customizable Branch Timings + + +For more comprehensive list of features [go here.](FEATURES.md) + + +## Getting Started + +To start using URY Pulse, you need to install URY and [Frappe HR](https://github.com/frappe/hrms#installation) and then setup your first restaurant. + +1. [URY Pulse Installation Guide](INSTALL.md). + +2. [URY Pulse Setup Instructions](SETUP.md). + + + +## About + +URY Pulse is developed by [Tridz Technologies Pvt Ltd](https://tridz.com) and supported by [Frappe](http://frappe.io). \ No newline at end of file diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..cc2373b --- /dev/null +++ b/SETUP.md @@ -0,0 +1,37 @@ + ## URY Pulse Setup + +Follow these steps to set up URY Pulse after completing basic ERPNext configuration: + +#### Step 1 : + +- Complete all the steps outlined in the [URY Setup](https://github.com/ury-erp/ury/blob/main/SETUP.md) + +#### Step 2: + +- Navigate to **URY Report Settings** in your site. +- Click on **Add URY Report Settings**. + +#### Step 3 + +- Under the **Details** tab: + - **Extended Hours** : Enable this if the branch operates after 12 AM. + - **No of Hours** : Enter the number of hours, if extended hours is enabled. +- Under the **Daily P and L Settings** tab: + - **Buying price List** : Select the buying price list for your branch. + - Under **Direct Expenses**: + - **Burning Materials (Other Consumables)** : Table to list consumables. + - **Material** : Enter the Material (e.g., gas, charcoal). + - **Cost Per Unit** : Specify the cost per unit for each material. + - **Direct Fixed Expenses** : Table to add list of daily fixed direct expenses. + - **Expense** : Provide the expense name. + - **Amount** : Specify amount for each expense. + - Under **Indirect Expenses**: + - **Electricity Charges**: Enter the electricity charges per unit. + - **Indirect Fixed Expenses** : Table to list daily fixed indirect expenses. + - **Expense** : Provide the expense name. + - **Amount** : Specify amount for each expense. + - **Percentage Expenses** : Table to list of expenses as a percentage of sales. + - **Expense** : Provide the expense name. + - **Percentage Type** : Choose the percentage type (Net Sales or Gross Sales). + - **Percent** : Specify the percentage of the selected type. + - **Depreciation** : Add depreciation amount if applicable. \ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..2fdf7c7 --- /dev/null +++ b/license.txt @@ -0,0 +1 @@ +License: MIT \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7668191 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +# frappe -- https://github.com/frappe/frappe is installed via 'bench init' \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0ecd00b --- /dev/null +++ b/setup.py @@ -0,0 +1,19 @@ +from setuptools import setup, find_packages + +with open("requirements.txt") as f: + install_requires = f.read().strip().split("\n") + +# get version from __version__ variable in ury_pulse/__init__.py +from ury_pulse import __version__ as version + +setup( + name="ury_pulse", + version=version, + description="Reporting Tool For Restaurants", + author="Tridz Technologies Pvt. Ltd.", + author_email="info@tridz.com", + packages=find_packages(), + zip_safe=False, + include_package_data=True, + install_requires=install_requires +) diff --git a/ury_pulse/__init__.py b/ury_pulse/__init__.py new file mode 100644 index 0000000..7a0660b --- /dev/null +++ b/ury_pulse/__init__.py @@ -0,0 +1,3 @@ + +__version__ = '0.0.1' + diff --git a/ury_pulse/config/__init__.py b/ury_pulse/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/config/desktop.py b/ury_pulse/config/desktop.py new file mode 100644 index 0000000..3974147 --- /dev/null +++ b/ury_pulse/config/desktop.py @@ -0,0 +1,10 @@ +from frappe import _ + +def get_data(): + return [ + { + "module_name": "URY Pulse", + "type": "module", + "label": _("URY Pulse") + } + ] diff --git a/ury_pulse/config/docs.py b/ury_pulse/config/docs.py new file mode 100644 index 0000000..7ed93a4 --- /dev/null +++ b/ury_pulse/config/docs.py @@ -0,0 +1,10 @@ +""" +Configuration for docs +""" + +# source_link = "https://github.com/[org_name]/ury_pulse" +# headline = "App that does everything" +# sub_heading = "Yes, you got that right the first time, everything" + +def get_context(context): + context.brand_html = "URY Pulse" diff --git a/ury_pulse/hooks.py b/ury_pulse/hooks.py new file mode 100644 index 0000000..e235790 --- /dev/null +++ b/ury_pulse/hooks.py @@ -0,0 +1,217 @@ +from . import __version__ as app_version + +app_name = "ury_pulse" +app_title = "URY Pulse" +app_publisher = "Tridz Technologies Pvt. Ltd." +app_description = "Reporting Tool For Restaurants" +app_email = "info@tridz.com" +app_license = "MIT" + +# Includes in +# ------------------ + +# include js, css files in header of desk.html +# app_include_css = "/assets/ury_pulse/css/ury_pulse.css" +# app_include_js = "/assets/ury_pulse/js/ury_pulse.js" + +# include js, css files in header of web template +# web_include_css = "/assets/ury_pulse/css/ury_pulse.css" +# web_include_js = "/assets/ury_pulse/js/ury_pulse.js" + +# include custom scss in every website theme (without file extension ".scss") +# website_theme_scss = "ury_pulse/public/scss/website" + +# include js, css files in header of web form +# webform_include_js = {"doctype": "public/js/doctype.js"} +# webform_include_css = {"doctype": "public/css/doctype.css"} + +# include js in page +# page_js = {"page" : "public/js/file.js"} + +# include js in doctype views +# doctype_js = {"doctype" : "public/js/doctype.js"} +# doctype_list_js = {"doctype" : "public/js/doctype_list.js"} +# doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} +# doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} + +# Home Pages +# ---------- + +# application home page (will override Website Settings) +# home_page = "login" + +# website user home page (by Role) +# role_home_page = { +# "Role": "home_page" +# } + +# Generators +# ---------- + +# automatically create page for each record of this doctype +# website_generators = ["Web Page"] + +# Jinja +# ---------- + +# add methods and filters to jinja environment +# jinja = { +# "methods": "ury_pulse.utils.jinja_methods", +# "filters": "ury_pulse.utils.jinja_filters" +# } + +# Installation +# ------------ + +# before_install = "ury_pulse.install.before_install" +# after_install = "ury_pulse.install.after_install" + +# Uninstallation +# ------------ + +# before_uninstall = "ury_pulse.uninstall.before_uninstall" +# after_uninstall = "ury_pulse.uninstall.after_uninstall" + +# Integration Setup +# ------------------ +# To set up dependencies/integrations with other apps +# Name of the app being installed is passed as an argument + +# before_app_install = "ury_pulse.utils.before_app_install" +# after_app_install = "ury_pulse.utils.after_app_install" + +# Integration Cleanup +# ------------------- +# To clean up dependencies/integrations with other apps +# Name of the app being uninstalled is passed as an argument + +# before_app_uninstall = "ury_pulse.utils.before_app_uninstall" +# after_app_uninstall = "ury_pulse.utils.after_app_uninstall" + +# Desk Notifications +# ------------------ +# See frappe.core.notifications.get_notification_config + +# notification_config = "ury_pulse.notifications.get_notification_config" + +# Permissions +# ----------- +# Permissions evaluated in scripted ways + +# permission_query_conditions = { +# "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", +# } +# +# has_permission = { +# "Event": "frappe.desk.doctype.event.event.has_permission", +# } + +# DocType Class +# --------------- +# Override standard doctype classes + +# override_doctype_class = { +# "ToDo": "custom_app.overrides.CustomToDo" +# } + +# Document Events +# --------------- +# Hook on document methods and events + +# doc_events = { +# "*": { +# "on_update": "method", +# "on_cancel": "method", +# "on_trash": "method" +# } +# } + +# Scheduled Tasks +# --------------- + +# scheduler_events = { +# "all": [ +# "ury_pulse.tasks.all" +# ], +# "daily": [ +# "ury_pulse.tasks.daily" +# ], +# "hourly": [ +# "ury_pulse.tasks.hourly" +# ], +# "weekly": [ +# "ury_pulse.tasks.weekly" +# ], +# "monthly": [ +# "ury_pulse.tasks.monthly" +# ], +# } + +# Testing +# ------- + +# before_tests = "ury_pulse.install.before_tests" + +# Overriding Methods +# ------------------------------ +# +# override_whitelisted_methods = { +# "frappe.desk.doctype.event.event.get_events": "ury_pulse.event.get_events" +# } +# +# each overriding function accepts a `data` argument; +# generated from the base implementation of the doctype dashboard, +# along with any modifications made in other Frappe apps +# override_doctype_dashboards = { +# "Task": "ury_pulse.task.get_dashboard_data" +# } + +# exempt linked doctypes from being automatically cancelled +# +# auto_cancel_exempted_doctypes = ["Auto Repeat"] + +# Ignore links to specified DocTypes when deleting documents +# ----------------------------------------------------------- + +# ignore_links_on_delete = ["Communication", "ToDo"] + +# Request Events +# ---------------- +# before_request = ["ury_pulse.utils.before_request"] +# after_request = ["ury_pulse.utils.after_request"] + +# Job Events +# ---------- +# before_job = ["ury_pulse.utils.before_job"] +# after_job = ["ury_pulse.utils.after_job"] + +# User Data Protection +# -------------------- + +# user_data_fields = [ +# { +# "doctype": "{doctype_1}", +# "filter_by": "{filter_by}", +# "redact_fields": ["{field_1}", "{field_2}"], +# "partial": 1, +# }, +# { +# "doctype": "{doctype_2}", +# "filter_by": "{filter_by}", +# "partial": 1, +# }, +# { +# "doctype": "{doctype_3}", +# "strict": False, +# }, +# { +# "doctype": "{doctype_4}" +# } +# ] + +# Authentication and authorization +# -------------------------------- + +# auth_hooks = [ +# "ury_pulse.auth.validate" +# ] diff --git a/ury_pulse/modules.txt b/ury_pulse/modules.txt new file mode 100644 index 0000000..fe70757 --- /dev/null +++ b/ury_pulse/modules.txt @@ -0,0 +1 @@ +URY Pulse \ No newline at end of file diff --git a/ury_pulse/patches.txt b/ury_pulse/patches.txt new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/public/.gitkeep b/ury_pulse/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/templates/__init__.py b/ury_pulse/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/templates/pages/__init__.py b/ury_pulse/templates/pages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/__init__.py b/ury_pulse/ury_pulse/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/__init__.py b/ury_pulse/ury_pulse/doctype/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/__init__.py b/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.json b/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.json new file mode 100644 index 0000000..f75a4b8 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.json @@ -0,0 +1,84 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-05 11:50:56.628931", + "default_view": "List", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "item_group", + "qty", + "buying_price", + "amount" + ], + "fields": [ + { + "columns": 2, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item", + "options": "Item", + "reqd": 1 + }, + { + "columns": 2, + "fetch_from": "item_code.item_name", + "fieldname": "item_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Item Name", + "reqd": 1 + }, + { + "columns": 2, + "fetch_from": "item_code.item_group", + "fieldname": "item_group", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Group", + "options": "Item Group", + "reqd": 1 + }, + { + "columns": 1, + "fieldname": "qty", + "fieldtype": "Int", + "in_list_view": 1, + "label": "Quantity", + "reqd": 1 + }, + { + "columns": 1, + "fieldname": "buying_price", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Buying Price", + "precision": "2", + "reqd": 1 + }, + { + "columns": 2, + "fieldname": "amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "precision": "2", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-05 17:23:42.710790", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Cost Of Goods", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.py b/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.py new file mode 100644 index 0000000..3ffd123 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_cost_of_goods/ury_cost_of_goods.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYCostOfGoods(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/__init__.py b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html new file mode 100644 index 0000000..df55047 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html @@ -0,0 +1,129 @@ +
+
+
+
+ +
+

{{ data.branch }}

+

Date: {{ data.date }}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% for expense in data.indirect_expenses_breakup %} + + + + + + {% endfor %} + + + + + + + + + + + + + + + + + + + + + +
{{ _("REVENUE") }}{{ _("AMOUNT") }}{{ _("PERCENTAGE") }}
{{ _('Gross Sales') }}{{ frappe.utils.fmt_money(data.gross_sales or '', currency=currency) }}{{ data.gross_sales_percent }}%
{{ _('Discounts & Round Offs') }}{{ frappe.utils.fmt_money(data.cash_discount_round_off or '', currency=currency) }}{{ data.cash_discount_round_off_percent }}%
{{ _('Tax') }}{{ frappe.utils.fmt_money(data.tax or '', currency=currency) }}{{ data.tax_percent }}%
{{ _('Net Sales') }}{{ frappe.utils.fmt_money(data.net_sales or '', currency=currency) }}{{ data.net_sales_percent }}%
{{ _('Cost of Goods Sold') }}{{ frappe.utils.fmt_money(data.cogs or '', currency=currency) }}{{ data.cogs_percent }}%
{{ _('Direct Expenses') }}{{ frappe.utils.fmt_money(data.total_direct_expenses or '', currency=currency) }}{{ data.total_direct_expenses_percent }}%
{{ _('Gross Profit/Loss') }}{{ frappe.utils.fmt_money(data.gross_profit or '', currency=currency) }}{{ data.gross_profit_percent }}%
{{ expense.breakup }}{{ expense.amount }}{{ expense.percent }}%
{{ _('Other Expenses') }}{{ frappe.utils.fmt_money(data.total_other_expenses or '', currency=currency) }}{{ data.other_expenses_percent }}%
{{ _('Depreciation') }}{{ frappe.utils.fmt_money(data.depreciation or '', currency=currency) }}{{ data.depreciation_percent }}%
{{ _('Total Indirect Expenses') }}{{ frappe.utils.fmt_money(data.total_indirect_expenses or '', currency=currency) }}{{ data.total_indirect_expenses_percent }}%
{{ _('Net Profit/Loss') }}{{ frappe.utils.fmt_money(data.net_profit or '', currency=currency) }}{{ data.net_profit_percent }}%
+
+
+
+
+
diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/test_ury_daily_p_and_l.py b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/test_ury_daily_p_and_l.py new file mode 100644 index 0000000..fe213e9 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/test_ury_daily_p_and_l.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestURYDailyPandL(FrappeTestCase): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.js b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.js new file mode 100644 index 0000000..7ac0e62 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.js @@ -0,0 +1,77 @@ +// Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('URY Daily P and L', { + refresh: function(frm) { + console.log("HOOOOOI") + frm.page.wrapper.find(".comment-box").css({'display':'none'}); + //restrict adding rows + frm.set_df_property('materials_consumed', 'cannot_add_rows', true); + //restrict deleting rows + frm.set_df_property('materials_consumed', 'cannot_delete_rows', true); + if(frm.doc.docstatus === 1){ + set_html_data(frm) + $('#ury-daily-p-and-l-profit_loss_tab-tab').click(); + } + }, + onload: function(frm) { + if (frm.doc.remarks !== "" && frm.doc.docstatus === 0){ + frm.set_value("remarks",""); + } + }, + branch: function(frm){ + if(frm.doc.branch === ""){ + frm.set_value("materials_consumed",[]) + } + else{ + frappe.db.exists('URY Report Settings', frm.doc.branch).then(report_settings_exist => { + if(report_settings_exist){ + frm.set_value("materials_consumed",[]) + frappe.db.get_doc('URY Report Settings', frm.doc.branch).then(report_settings => { + // Access the child table data from Report Settings + console.log(report_settings) + + report_settings.consumables.forEach(materials_data_item => { + + const newRow = frappe.model.add_child(frm.doc, 'materials_consumed'); + + newRow.material = materials_data_item.material; + newRow.cost_per_unit = materials_data_item.cost_per_unit; + newRow.material = materials_data_item.material; + + // Save the current document + frm.refresh_field('materials_consumed'); + }) + }); + } + else{ + frappe.throw({ + title: __("Missing URY Report Settings"), + message: __("Please set up URY Report Settings for the selected branch: {0}", [frm.doc.branch]), + }); + frm.set_value("materials_consumed",[]) + } + }); + } + } +}); + +function set_html_data(frm) { + if (frm.doc.docstatus === 1) { + frappe.call({ + method: "get_proft_loss_details", + doc: frm.doc, + callback: (r) => { + frm.get_field("proft_loss_details").$wrapper.html(r.message); + } + }); + } +} + +frappe.ui.form.on('URY P and L Materials', { + units_consumed: function(frm, cdt, cdn) { + var row = locals[cdt][cdn]; + row.amount = row.cost_per_unit*row.units_consumed + frm.refresh_fields(); + } +}); diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json new file mode 100644 index 0000000..a169e2b --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.json @@ -0,0 +1,457 @@ +{ + "actions": [], + "autoname": "Daily-PL-.YYYY.-.#####", + "creation": "2023-10-05 16:43:50.108202", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "profit_loss_tab", + "proft_loss_details", + "p_and_l_section", + "gross_sales", + "online_sales", + "cash_discount_round_off", + "tax", + "net_sales", + "cogs", + "total_direct_expenses", + "gross_profit", + "total_employee_costs", + "depreciation", + "total_other_expenses", + "total_indirect_expenses", + "net_profit", + "column_break_bqo3d", + "gross_sales_percent", + "online_sales_percent", + "cash_discount_round_off_percent", + "tax_percent", + "net_sales_percent", + "cogs_percent", + "total_direct_expenses_percent", + "gross_profit_percent", + "total_employee_costs_percent", + "depreciation_percent", + "other_expenses_percent", + "total_indirect_expenses_percent", + "net_profit_percent", + "details_tab", + "branch", + "column_break_so5qh", + "date", + "section_break_qpbbd", + "electricity_opening", + "column_break_mq2bv", + "electricity_closing", + "section_break_6mqsm", + "materials_consumed", + "section_break_dv4iu", + "other_expenses", + "remarks", + "expenses_breakup", + "direct_expenses_breakup", + "section_break_lught", + "employee_costs_breakup", + "section_break_rhkwy", + "indirect_expenses_breakup", + "cogs_tab", + "cost_of_goods", + "amended_from" + ], + "fields": [ + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "proft_loss_details", + "fieldtype": "HTML" + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Branch", + "options": "Branch", + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "column_break_so5qh", + "fieldtype": "Column Break" + }, + { + "fieldname": "date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Date", + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "section_break_qpbbd", + "fieldtype": "Section Break" + }, + { + "description": "opening reading(Unit)", + "fieldname": "electricity_opening", + "fieldtype": "Float", + "label": "Electricity Opening", + "precision": "2", + "read_only_depends_on": "eval:doc.docstatus==1", + "reqd": 1 + }, + { + "fieldname": "column_break_mq2bv", + "fieldtype": "Column Break" + }, + { + "description": "closing reading(Unit)", + "fieldname": "electricity_closing", + "fieldtype": "Float", + "label": "Electricity Closing", + "precision": "2", + "read_only_depends_on": "eval:doc.docstatus==1", + "reqd": 1 + }, + { + "fieldname": "other_expenses", + "fieldtype": "Table", + "label": "Other Expenses", + "options": "URY P and L Breakup", + "read_only_depends_on": "eval:doc.docstatus==1" + }, + { + "collapsible": 1, + "fieldname": "p_and_l_section", + "fieldtype": "Section Break", + "label": "Summary" + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "gross_sales", + "fieldtype": "Currency", + "label": "Gross Sales", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "gross_sales_percent", + "fieldtype": "Percent", + "label": "Gross Sales Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "online_sales", + "fieldtype": "Currency", + "label": "Online Sales", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "online_sales_percent", + "fieldtype": "Percent", + "label": "Online Sales Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "cash_discount_round_off", + "fieldtype": "Currency", + "label": "Discounts & Round Offs", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "cash_discount_round_off_percent", + "fieldtype": "Percent", + "label": "Discounts & Round Offs Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "tax", + "fieldtype": "Currency", + "label": "Tax", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "tax_percent", + "fieldtype": "Percent", + "label": "Tax Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "net_sales", + "fieldtype": "Currency", + "label": "Net Sales", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "net_sales_percent", + "fieldtype": "Percent", + "label": "Net Sales Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "cogs", + "fieldtype": "Currency", + "label": "Cost of Goods Sold", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "cogs_percent", + "fieldtype": "Percent", + "label": "Cost of Goods Sold Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_direct_expenses", + "fieldtype": "Currency", + "label": "Total Direct Expense", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_direct_expenses_percent", + "fieldtype": "Percent", + "label": "Total Direct Expense Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "gross_profit", + "fieldtype": "Currency", + "label": "Gross Profit/Loss", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "gross_profit_percent", + "fieldtype": "Percent", + "label": "Gross Profit/Loss Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "depreciation", + "fieldtype": "Currency", + "label": "Depreciation", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "depreciation_percent", + "fieldtype": "Percent", + "label": "Depreciation Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_other_expenses", + "fieldtype": "Currency", + "label": "Other Expenses", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "other_expenses_percent", + "fieldtype": "Percent", + "label": "Other Expenses Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_indirect_expenses", + "fieldtype": "Currency", + "label": "Total Indirect Expenses", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_indirect_expenses_percent", + "fieldtype": "Percent", + "label": "Total Indirect Expenses Percent", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "net_profit", + "fieldtype": "Currency", + "label": "Net Profit/Loss", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "net_profit_percent", + "fieldtype": "Percent", + "label": "Net Profit/Loss Percent", + "read_only": 1 + }, + { + "fieldname": "expenses_breakup", + "fieldtype": "Tab Break", + "label": "Breakup" + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "direct_expenses_breakup", + "fieldtype": "Table", + "label": "Direct Expenses", + "options": "URY P and L Breakup", + "read_only": 1 + }, + { + "fieldname": "section_break_lught", + "fieldtype": "Section Break" + }, + { + "depends_on": "eval:doc.docstatus==1", + "description": "Includes in Total Indirect Expense", + "fieldname": "employee_costs_breakup", + "fieldtype": "Table", + "label": "Employee Costs", + "options": "URY P and L Breakup", + "read_only": 1 + }, + { + "fieldname": "section_break_rhkwy", + "fieldtype": "Section Break" + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "indirect_expenses_breakup", + "fieldtype": "Table", + "label": "Indirect Expenses", + "options": "URY P and L Breakup", + "read_only": 1 + }, + { + "fieldname": "cogs_tab", + "fieldtype": "Tab Break", + "label": "Cost Of Goods" + }, + { + "fieldname": "cost_of_goods", + "fieldtype": "Table", + "label": "Cost Of Goods Sold (Breakup)", + "options": "URY Cost Of Goods", + "read_only": 1 + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "URY Daily P and L", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "section_break_6mqsm", + "fieldtype": "Section Break" + }, + { + "fieldname": "remarks", + "fieldtype": "Long Text", + "label": "Remarks", + "read_only": 1 + }, + { + "fieldname": "section_break_dv4iu", + "fieldtype": "Section Break" + }, + { + "fieldname": "details_tab", + "fieldtype": "Tab Break", + "label": "Details" + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_employee_costs", + "fieldtype": "Currency", + "label": "Employee Cost", + "precision": "2", + "read_only": 1 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "total_employee_costs_percent", + "fieldtype": "Percent", + "label": "Employee Cost Percent", + "read_only": 1 + }, + { + "fieldname": "profit_loss_tab", + "fieldtype": "Tab Break", + "label": "Profit / Loss" + }, + { + "fieldname": "column_break_bqo3d", + "fieldtype": "Column Break" + }, + { + "description": "Enter Units Consumed", + "fieldname": "materials_consumed", + "fieldtype": "Table", + "label": "Materials Consumed", + "options": "URY P and L Materials" + } + ], + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [], + "modified": "2023-10-25 18:43:16.678877", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Daily P and L", + "naming_rule": "Expression (old style)", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "URY Manager", + "share": 1, + "submit": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py new file mode 100644 index 0000000..810a680 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_daily_p_and_l/ury_daily_p_and_l.py @@ -0,0 +1,297 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document +import json +import calendar +from datetime import datetime + +class URYDailyPandL(Document): + def cogs_sold(self): + report_settings = frappe.get_doc("URY Report Settings",self.branch) + self.cost_of_goods = [] + cogs = 0 + electricity_reading = self.electricity_closing - self.electricity_opening + if electricity_reading <= 0: + frappe.throw("Invalid Electricity Reading") + + # Append materials consumed + for expense in self.materials_consumed: + if expense.units_consumed <= 0: + frappe.throw("Invavlid Units Consumed for "+expense.material) + non_pb_item_sales = frappe.db.sql(''' + SELECT + c.item_group AS "Item Group", + c.item_code AS "Item Code", + c.item_name AS "Item Name", + SUM(b.qty) AS "Qty" + FROM `tabPOS Invoice` a + INNER JOIN `tabPOS Invoice Item` b ON a.name = b.parent + LEFT JOIN `tabItem` c ON c.item_code = b.item_code + LEFT JOIN `tabProduct Bundle` d ON d.new_item_code = b.item_code + WHERE + a.`branch` = %(branch)s + AND a.`status` IN ("Consolidated", "Paid") + AND a.`docstatus` = 1 + AND TIMESTAMP(a.`posting_date`, a.`posting_time`) >= TIMESTAMP(%(date)s, '05:02:00') + AND TIMESTAMP(a.`posting_date`, a.`posting_time`) <= TIMESTAMP(DATE_ADD(%(date)s, INTERVAL 1 DAY), '05:00:00') + AND d.new_item_code IS NULL + GROUP BY + c.item_name + ORDER BY + c.item_group ASC, b.item_name ASC + ''', {"branch": self.branch, "date": self.date}, as_dict=True) + + pb_item_sales = frappe.db.sql(''' + SELECT + c.item_group AS "Item Group", + c.item_code AS "Item Code", + c.item_name AS "Item Name", + SUM(b.qty) AS "Qty" + FROM `tabPOS Invoice` a + INNER JOIN `tabPOS Invoice Item` b ON a.name = b.parent + LEFT JOIN `tabItem` c ON c.item_code = b.item_code + LEFT JOIN `tabProduct Bundle` d ON d.new_item_code = b.item_code + WHERE + a.`branch` = %(branch)s + AND a.`status` IN ("Consolidated", "Paid") + AND a.`docstatus` = 1 + AND TIMESTAMP(a.`posting_date`, a.`posting_time`) >= TIMESTAMP(%(date)s, '05:02:00') + AND TIMESTAMP(a.`posting_date`, a.`posting_time`) <= TIMESTAMP(DATE_ADD(%(date)s, INTERVAL 1 DAY), '05:00:00') + AND d.new_item_code IS NOT NULL + GROUP BY + c.item_name + ORDER BY + c.item_group ASC, b.item_name ASC + ''', {"branch": self.branch, "date": self.date}, as_dict=True) + + unset_item_prices = [] + for item in non_pb_item_sales: + items_price = frappe.db.get_all("Item Price",fields = ['name','price_list_rate'],filters = {'price_list':report_settings.buying_price_list,'item_code':item['Item Code']}) + item_name = item['Item Name'] + if len(items_price) == 0: + unset_item_prices.append(item_name) + else: + qty = int(item['Qty']) + self.append("cost_of_goods" ,{ + "item_code":item['Item Code'], + "item_name":item['Item Name'], + "item_group":item['Item Group'], + "qty":qty, + "buying_price":items_price[0].price_list_rate, + "amount":items_price[0].price_list_rate * qty + }) + cogs = cogs + items_price[0].price_list_rate * qty + + unset_pb_item_prices = [] + unset_bom_item_prices = [] + for item in pb_item_sales: + pb_items = frappe.db.get_all("Product Bundle",fields = ("*"),filters = {'new_item_code':item['Item Code']}) + pb = frappe.get_doc("Product Bundle",pb_items[0].name) + buying_price = 0 + for pb_item in pb.items: + item_qty = pb_item.qty + boms = frappe.db.get_all("BOM",fields = ("*"),filters = {'item':pb_item.item_code,'is_active':1,'is_default':1,'docstatus':1}) + if len(boms) > 0: + bom_buying_price = 0 + bom = frappe.get_doc("BOM",boms[0].name) + for bom_item in bom.items: + bom_item_qty = pb_item.qty + bom_item_name = bom_item.item_name + bom_items_price = frappe.db.get_all("Item Price",fields = ['name','price_list_rate'],filters = {'price_list':report_settings.buying_price_list,'item_code':bom_item.item_code}) + if len(bom_items_price) == 0: + if bom_item_name not in unset_bom_item_prices: + unset_bom_item_prices.append(bom_item_name) + else: + bom_buying_price += float(bom_items_price[0].price_list_rate)*bom_item_qty + bom_buying_price = bom_buying_price/bom.quantity + buying_price += float(bom_buying_price)*item_qty + else: + sub_item = frappe.get_doc("Item",pb_item.item_code) + item_name = sub_item.item_name + items_price = frappe.db.get_all("Item Price",fields = ['name','price_list_rate'],filters = {'price_list':report_settings.buying_price_list,'item_code':pb_item.item_code}) + if len(items_price) == 0: + if item_name not in unset_pb_item_prices: + unset_pb_item_prices.append(item_name) + else: + buying_price += float(items_price[0].price_list_rate)*item_qty + + if buying_price > 0: + qty = int(item['Qty']) + self.append("cost_of_goods" ,{ + "item_code":item['Item Code'], + "item_name":item['Item Name'], + "item_group":item['Item Group'], + "qty":qty, + "buying_price":buying_price, + "amount":buying_price * qty + }) + cogs = cogs + buying_price * qty + self.cogs = cogs + + unset_prices = [ + ("ITEMS", unset_item_prices), + ("BUNDLE SUB ITEMS", unset_pb_item_prices), + ("BOM SUB ITEMS", unset_bom_item_prices) + ] + remarks = "BUYING PRICE NOT SET

" + "

".join(f"{label}:-
{items}" for label, items in unset_prices if items) + if any(items for label, items in unset_prices): + remarks += "

Update the item prices and then submit the document again to ensure accurate Cost of Goods" + self.remarks = remarks + else: + self.remarks = "" + + + def before_save(self): + self.cogs_sold() + if self.remarks != "": + frappe.msgprint(title='SET BUYING PRICE',msg=("Please review the remarks below for the items. Submitting now will exclude these items from the cost of goods.")) + + def before_submit(self): + self.cogs_sold() + + report_settings = frappe.get_doc("URY Report Settings",self.branch) + + self.direct_expenses_breakup = [] + self.employee_costs_breakup = [] + self.indirect_expenses_breakup = [] + + '''Total Sales Of the Day''' + gross_sales = frappe.db.sql(''' + SELECT + %(date)s AS "Date", + COUNT(b.`name`) AS "Total Invoices", + ROUND(SUM(b.`net_total`),2) AS "Item Total", + ROUND(SUM(b.`grand_total` - b.`net_total`),2) AS "Tax", + ROUND(SUM(b.`grand_total`),2) AS "Grand Total", + ROUND(SUM(b.`grand_total` - b.`rounded_total`),2) AS "Round Off", + ROUND(SUM(b.`rounded_total`),2) AS "Rounded Total", + ROUND(SUM(b.`rounded_total` - b.`paid_amount` + b.`change_amount`),2) AS "Cash Discounts" + FROM `tabPOS Invoice` b + LEFT JOIN `tabReport Settings` rs ON ( + rs.`branch` = %(branch)s + ) + WHERE + b.`branch` = %(branch)s + AND b.`status` IN ("Consolidated", "Paid") + AND b.`docstatus` = 1 + AND + ( + (rs.`hours` IS NULL AND b.`posting_date` = %(date)s) + OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(%(date)s, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(%(date)s, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00'))) + OR (rs.`branch` IS NULL AND b.`posting_date` = %(date)s) + ) + ''', {"branch": self.branch, "date": self.date}, as_dict=True) + + + # GROSS AND NET SALES + self.gross_sales = 0.0 + gross_sales_all = gross_sales[0] + if gross_sales_all['Total Invoices'] == 0: + self.gross_sales = 0.0 + gross_sales = gross_sales[0] + gross_sales["Round Off"] = gross_sales["Cash Discounts"] = gross_sales["Tax"] = 0.0 + else: + gross_sales = gross_sales[0] + self.gross_sales = gross_sales["Grand Total"] + + self.cash_discount_round_off = round((gross_sales["Round Off"] + gross_sales["Cash Discounts"]),2) + self.tax = gross_sales["Tax"] + + self.net_sales = self.gross_sales - self.cash_discount_round_off - self.tax + + if self.net_sales == 0.0: + self.gross_sales_percent = self.cash_discount_round_off_percent = self.tax_percent = self.cogs_percent = self.total_direct_expenses_percent = self.gross_profit_percent = self.total_other_expenses_percent = self.depreciation_percent = self.total_indirect_expenses_percent = self.net_profit_percent = 0.0 + else: + self.gross_sales_percent = round(((self.gross_sales / self.net_sales) * 100),2) + self.cash_discount_round_off_percent = round(((self.cash_discount_round_off / self.net_sales) * 100),2) + self.tax_percent = round(((self.tax / self.net_sales) * 100),2) + + self.cogs_percent = round(((self.cogs / self.net_sales) * 100),2) + + self.net_sales_percent = 100.0 + + + # DIRECT EXPENSES + self.total_irect_expense = 0 + electricity_reading = self.electricity_closing - self.electricity_opening + + # Append materials consumed + for expense in self.materials_consumed: + self.append("direct_expenses_breakup", {"breakup": expense.material, "amount": expense.amount}) + self.total_direct_expenses += expense.amount + + # Append other fixed expenses + for expense in report_settings.direct_fixed_expenses: + self.append("direct_expenses_breakup", {"breakup": expense.expense, "amount": expense.amount}) + self.total_direct_expenses += expense.amount + + + # GROSS PROFIT + self.gross_profit = self.net_sales - self.total_direct_expenses - self.cogs + + if self.net_sales != 0.0: + self.total_direct_expenses_percent = round(((self.total_direct_expenses / self.net_sales) * 100),2) + self.gross_profit_percent = round(((self.gross_profit / self.net_sales) * 100),2) + + + '''INDIRECT EXPENSES''' + + #INDIRECT EXPENSES + + # Calculate and append Electricity + electricity_charges = electricity_reading * report_settings.electricity_charges + if self.net_sales != 0.0: + electricity_percent = round(((electricity_charges / self.net_sales) * 100),3) + else: + electricity_percent = 0.0 + self.append("indirect_expenses_breakup", {"breakup": "Electricity", "amount": electricity_charges,"percent":electricity_percent}) + + + # Append indirect fixed expenses + for expense in report_settings.indirect_fixed_expenses: + if self.net_sales != 0.0: + expense_percent = round(((expense.amount / self.net_sales) * 100),3) + else: + expense_percent = 0.0 + self.append("indirect_expenses_breakup", {"breakup": expense.expense, "amount": expense.amount,"percent":expense_percent}) + self.total_indirect_expenses += expense.amount + + # Calculate and append percentage expenses + for expense in report_settings.percentage_expenses: + if expense.percentage_type in ["Gross Sales", "Net Sales"]: + base_amount = self.gross_sales if expense.percentage_type == "Gross Sales" else self.net_sales + amount = round((expense.percent * base_amount) / 100, 2) + if self.net_sales != 0.0: + expense_percent = round(((amount / self.net_sales) * 100),3) + else: + expense_percent = 0.0 + self.append("indirect_expenses_breakup", {"breakup": expense.expense, "amount": amount ,"percent":expense_percent}) + self.total_indirect_expenses += amount + + # OTHER EXPENSES + self.total_other_expenses = 0 + for expense in self.other_expenses: + self.total_indirect_expenses += expense.amount + self.total_other_expenses += expense.amount + + self.depreciation = report_settings.depreciation + + self.total_indirect_expenses = self.total_indirect_expenses + self.depreciation + + # NET PROFIT + self.net_profit = self.gross_profit - self.total_indirect_expenses + + if self.net_sales != 0.0: + self.total_other_expenses_percent = round(((self.total_other_expenses / self.net_sales) * 100),3) + self.depreciation_percent = round(((self.depreciation / self.net_sales) * 100),3) + self.total_indirect_expenses_percent = round(((self.total_indirect_expenses / self.net_sales) * 100),2) + self.net_profit_percent = round(((self.net_profit / self.net_sales) * 100),2) + + @frappe.whitelist() + def get_proft_loss_details(self): + return frappe.render_template( + "ury_pulse/doctype/ury_daily_p_and_l/profit_loss_details.html", + {"data": self, "currency": "INR"}, + ) \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/__init__.py b/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.json b/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.json new file mode 100644 index 0000000..4c8b8db --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.json @@ -0,0 +1,41 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-04 14:47:45.370491", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "expense", + "amount" + ], + "fields": [ + { + "fieldname": "expense", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Expense", + "reqd": 1 + }, + { + "fieldname": "amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "precision": "2", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-05 16:04:21.456296", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Fixed Expenses", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.py b/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.py new file mode 100644 index 0000000..7e8e35a --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_fixed_expenses/ury_fixed_expenses.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYFixedExpenses(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_materials/__init__.py b/ury_pulse/ury_pulse/doctype/ury_materials/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.json b/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.json new file mode 100644 index 0000000..37d88e0 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.json @@ -0,0 +1,41 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-05 10:13:18.431268", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "material", + "cost_per_unit" + ], + "fields": [ + { + "fieldname": "cost_per_unit", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Cost Per Unit", + "precision": "2", + "reqd": 1 + }, + { + "fieldname": "material", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Material", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-06 11:51:25.022608", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Materials", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.py b/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.py new file mode 100644 index 0000000..b625359 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_materials/ury_materials.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYMaterials(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/__init__.py b/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.json b/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.json new file mode 100644 index 0000000..8827275 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.json @@ -0,0 +1,51 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-05 15:35:53.488494", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "breakup", + "amount", + "percent" + ], + "fields": [ + { + "columns": 2, + "fieldname": "breakup", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Breakup", + "reqd": 1 + }, + { + "columns": 2, + "fieldname": "amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "precision": "2", + "reqd": 1 + }, + { + "fieldname": "percent", + "fieldtype": "Percent", + "label": "Percent", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-06 18:48:52.491943", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY P and L Breakup", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.py b/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.py new file mode 100644 index 0000000..b9529d8 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_p_and_l_breakup/ury_p_and_l_breakup.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYPandLBreakup(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/__init__.py b/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.json b/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.json new file mode 100644 index 0000000..836c8f2 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.json @@ -0,0 +1,63 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-06 10:45:57.191236", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "material", + "cost_per_unit", + "units_consumed", + "amount" + ], + "fields": [ + { + "fieldname": "cost_per_unit", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Cost Per Unit", + "precision": "2", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "units_consumed", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Units Consumed", + "precision": "2", + "reqd": 1 + }, + { + "fieldname": "amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "options": "currency", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "material", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Material", + "read_only": 1, + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-06 11:51:11.653896", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY P and L Materials", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.py b/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.py new file mode 100644 index 0000000..e1d80ec --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_p_and_l_materials/ury_p_and_l_materials.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYPandLMaterials(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/__init__.py b/ury_pulse/ury_pulse/doctype/ury_report_settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/test_ury_report_settings.py b/ury_pulse/ury_pulse/doctype/ury_report_settings/test_ury_report_settings.py new file mode 100644 index 0000000..3a9eb82 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_report_settings/test_ury_report_settings.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestURYReportSettings(FrappeTestCase): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.js b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.js new file mode 100644 index 0000000..ab95a02 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.js @@ -0,0 +1,27 @@ +// Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('URY Report Settings', { + refresh: function(frm) { + frm.page.wrapper.find(".comment-box").css({'display':'none'}); + frm.set_query("buying_price_list", function() { + return { + "filters": { + "buying":1 + } + } + }); + if(frm.doc.__islocal){ + frm.clear_table('consumables'); + frm.add_child('consumables', { + material:"Gas", + cost_per_unit: 0.0 + }); + frm.add_child('consumables', { + material:"Charcoal", + cost_per_unit: 0.0 + }); + frm.refresh_field('consumables'); + } + } +}); diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json new file mode 100644 index 0000000..f4a5211 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.json @@ -0,0 +1,188 @@ +{ + "actions": [], + "autoname": "field:branch", + "creation": "2023-09-29 10:45:19.994545", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "branch", + "extended_hours", + "hours", + "daily_p_and_l", + "buying_price_list", + "direct_expense_section", + "consumables", + "direct_fixed_expenses", + "indirect_expense_section", + "electricity_charges", + "indirect_fixed_expenses", + "percentage_expenses", + "employee_costs_section", + "bonus", + "staff_accommodation_charges", + "staff_food_charges", + "section_break_4c2bz", + "depreciation" + ], + "fields": [ + { + "fieldname": "branch", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Branch", + "options": "Branch", + "reqd": 1, + "unique": 1 + }, + { + "default": "0", + "description": "Whether the branch is open after 12 AM.", + "fieldname": "extended_hours", + "fieldtype": "Check", + "label": "Extended Hours", + "reqd": 1 + }, + { + "depends_on": "eval:doc.extended_hours==1", + "fieldname": "hours", + "fieldtype": "Int", + "label": "No Of Hours", + "mandatory_depends_on": "eval:doc.extended_hours==1", + "non_negative": 1 + }, + { + "fieldname": "daily_p_and_l", + "fieldtype": "Tab Break", + "label": "Daily P and L Settings" + }, + { + "fieldname": "buying_price_list", + "fieldtype": "Link", + "label": "Buying Price List", + "options": "Price List", + "reqd": 1 + }, + { + "collapsible": 1, + "fieldname": "direct_expense_section", + "fieldtype": "Section Break", + "label": "Direct Expenses" + }, + { + "description": "Daily Fixed", + "fieldname": "direct_fixed_expenses", + "fieldtype": "Table", + "label": "Direct Fixed Expenses", + "options": "URY Fixed Expenses" + }, + { + "collapsible": 1, + "fieldname": "indirect_expense_section", + "fieldtype": "Section Break", + "label": "Indirect Expenses", + "options": "Staff Food Charges" + }, + { + "description": "Daily Fixed", + "fieldname": "indirect_fixed_expenses", + "fieldtype": "Table", + "label": "Indirect Fixed Expenses", + "options": "URY Fixed Expenses" + }, + { + "fieldname": "percentage_expenses", + "fieldtype": "Table", + "label": "Percentage Expenses", + "options": "URY Variable Expenses" + }, + { + "description": "Daily Fixed", + "fieldname": "depreciation", + "fieldtype": "Currency", + "label": "Depreciation", + "precision": "2" + }, + { + "collapsible": 1, + "description": "
  • Daily Gross Salary Cost is calculated from employees attendance.
  • \n
    ", + "fieldname": "employee_costs_section", + "fieldtype": "Section Break", + "hidden": 1, + "label": "Employee Costs" + }, + { + "fieldname": "bonus", + "fieldtype": "Currency", + "label": "Bonus", + "precision": "2" + }, + { + "fieldname": "staff_food_charges", + "fieldtype": "Currency", + "label": "Staff Food Charges", + "precision": "2" + }, + { + "fieldname": "section_break_4c2bz", + "fieldtype": "Section Break" + }, + { + "fieldname": "staff_accommodation_charges", + "fieldtype": "Currency", + "label": "Staff Accommodation Charges", + "precision": "2" + }, + { + "description": "Per Unit", + "fieldname": "electricity_charges", + "fieldtype": "Currency", + "label": "Electricty Charges" + }, + { + "fieldname": "consumables", + "fieldtype": "Table", + "label": "Burning Materials (Other Consumables)", + "options": "URY Materials" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-10-25 18:42:45.149783", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Report Settings", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "URY Manager", + "select": 1, + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.py b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.py new file mode 100644 index 0000000..d4f6116 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_report_settings/ury_report_settings.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYReportSettings(Document): + pass diff --git a/ury_pulse/ury_pulse/doctype/ury_variable_expenses/__init__.py b/ury_pulse/ury_pulse/doctype/ury_variable_expenses/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.json b/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.json new file mode 100644 index 0000000..ab3f938 --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.json @@ -0,0 +1,51 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-10-04 14:54:32.483102", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "expense", + "percentage_type", + "percent" + ], + "fields": [ + { + "fieldname": "expense", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Expense", + "reqd": 1 + }, + { + "fieldname": "percentage_type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Percentage Type", + "options": "Gross Sales\nNet Sales", + "reqd": 1 + }, + { + "description": "% of selected sales", + "fieldname": "percent", + "fieldtype": "Percent", + "in_list_view": 1, + "label": "Percent", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-10-05 17:25:47.313238", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "URY Variable Expenses", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.py b/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.py new file mode 100644 index 0000000..520949b --- /dev/null +++ b/ury_pulse/ury_pulse/doctype/ury_variable_expenses/ury_variable_expenses.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Tridz Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class URYVariableExpenses(Document): + pass diff --git a/ury_pulse/ury_pulse/report/__init__.py b/ury_pulse/ury_pulse/report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/average_bill_value/__init__.py b/ury_pulse/ury_pulse/report/average_bill_value/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/average_bill_value/average_bill_value.json b/ury_pulse/ury_pulse/report/average_bill_value/average_bill_value.json new file mode 100644 index 0000000..2415197 --- /dev/null +++ b/ury_pulse/ury_pulse/report/average_bill_value/average_bill_value.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2023-09-29 14:49:49.209829", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:52:34.320532", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Average Bill Value", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT\n date_list.`date` AS \"Date\",\n COUNT(b.name) AS \"Bill Nos:Link/POS Invoice\",\n ROUND(SUM(b.grand_total),2) AS \"Total Sales\",\n ROUND((SUM(b.grand_total)/count(b.name)),2) AS \"ABV\"\n \nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1\n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n)\nGROUP BY \n date_list.`date`\nORDER BY \n date_list.`date` DESC", + "ref_doctype": "POS Invoice", + "report_name": "Average Bill Value", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/cancelled_invoices/__init__.py b/ury_pulse/ury_pulse/report/cancelled_invoices/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/cancelled_invoices/cancelled_invoices.json b/ury_pulse/ury_pulse/report/cancelled_invoices/cancelled_invoices.json new file mode 100644 index 0000000..c5d3aad --- /dev/null +++ b/ury_pulse/ury_pulse/report/cancelled_invoices/cancelled_invoices.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2023-09-29 14:50:36.967491", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:53:00.834354", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Cancelled Invoices", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT \n b.`posting_date` AS \"Date\",\n CONCAT(\n LPAD(IF(HOUR(b.`posting_time`) > 12, HOUR(b.`posting_time`) - 12, HOUR(b.`posting_time`)), 2, '0'),\n ':',\n SUBSTRING_INDEX(SUBSTRING_INDEX(b.`posting_time`, ':', 2), ':', -1),\n CASE WHEN HOUR(b.`posting_time`) >= 12 THEN ' PM' ELSE ' AM' END\n ) AS \"Time\",\n b.`name` AS \"Invoice:Link/POS Invoice\",\n b.`modified_by` AS \"Cancelled By\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n \n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`docstatus` = 2 \n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n)\nGROUP BY \n date_list.`date`,b.`name`\nORDER BY \n date_list.`date` ASC, b.`name` ASC", + "ref_doctype": "POS Invoice", + "report_name": "Cancelled Invoices", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/customer_data/__init__.py b/ury_pulse/ury_pulse/report/customer_data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/customer_data/customer_data.json b/ury_pulse/ury_pulse/report/customer_data/customer_data.json new file mode 100644 index 0000000..06b3dc5 --- /dev/null +++ b/ury_pulse/ury_pulse/report/customer_data/customer_data.json @@ -0,0 +1,64 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2023-09-29 14:51:46.583438", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + }, + { + "fieldname": "customer", + "fieldtype": "Link", + "label": "Customer", + "mandatory": 1, + "options": "Customer", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:53:34.430300", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Customer Data", + "owner": "Administrator", + "prepared_report": 0, + "query": "select\n b.`posting_date` AS \"Date\",\n b.name AS \"POS Invoice:Link/POS Invoice\",\n b.customer_name AS \"Customer Name\",\n b.mobile_number AS \"Mobile Number\",\n b.total AS \"Total Amount\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1\n AND b.customer_name = %(customer)s\n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n)\nGROUP BY \n date_list.`date`,b.`name`\nORDER BY \n date_list.`date` ASC, b.`name` ASC", + "ref_doctype": "POS Invoice", + "report_name": "Customer Data", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/daywise_invoices/__init__.py b/ury_pulse/ury_pulse/report/daywise_invoices/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/daywise_invoices/daywise_invoices.json b/ury_pulse/ury_pulse/report/daywise_invoices/daywise_invoices.json new file mode 100644 index 0000000..54200c2 --- /dev/null +++ b/ury_pulse/ury_pulse/report/daywise_invoices/daywise_invoices.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2023-09-29 14:47:56.403837", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:52:06.012622", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Daywise Invoices", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT \n b.`posting_date` AS \"Date\",\n CONCAT(\n LPAD(IF(HOUR(b.`posting_time`) > 12, HOUR(b.`posting_time`) - 12, HOUR(b.`posting_time`)), 2, '0'),\n ':',\n SUBSTRING_INDEX(SUBSTRING_INDEX(b.`posting_time`, ':', 2), ':', -1),\n CASE WHEN HOUR(b.`posting_time`) >= 12 THEN ' PM' ELSE ' AM' END\n ) AS \"Time\",\n b.`name` AS \"Invoice:Link/POS Invoice\",\n b.`net_total` AS \"Item Total\",\n b.`total_taxes_and_charges` AS \"Total Taxes and Charges\",\n b.`grand_total` AS \"Grand Total\",\n (b.`grand_total` - b.`rounded_total`) AS \"Round Off\",\n b.`rounded_total` AS \"Rounded Total\",\n CASE WHEN b.`customer_group` = 'Aggregators' THEN 0 ELSE b.`paid_amount` END AS \"Received Amount\",\n CASE WHEN b.`customer_group` = 'Aggregators' THEN 0 ELSE b.`change_amount` END AS \"Change Amount\",\n IFNULL((SELECT (b.`rounded_total` - b.`paid_amount` + b.`change_amount`)), 0)AS \"Cash Discounts\",\n GROUP_CONCAT(\n CASE WHEN c.`amount` != 0 THEN c.`mode_of_payment` END \n ORDER BY c.`amount` \n SEPARATOR ', '\n ) AS \"Payment Mode\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1\n)\nLEFT JOIN `tabSales Invoice Payment` c ON (\n c.`parent`= b.`name`\n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n (\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n )\nGROUP BY \n date_list.`date`,b.`name`\nORDER BY \n date_list.`date` ASC, b.`name` ASC", + "ref_doctype": "POS Invoice", + "report_name": "Daywise Invoices", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/daywise_sales/__init__.py b/ury_pulse/ury_pulse/report/daywise_sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/daywise_sales/daywise_sales.json b/ury_pulse/ury_pulse/report/daywise_sales/daywise_sales.json new file mode 100644 index 0000000..d9d67c1 --- /dev/null +++ b/ury_pulse/ury_pulse/report/daywise_sales/daywise_sales.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2023-09-29 14:46:17.686947", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:51:50.796293", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Daywise Sales", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT \n date_list.`date` AS \"Date\",\n COUNT(b.`name`) AS \"Total Invoices\",\n ROUND(SUM(b.`net_total`),2) AS \"Item Total\",\n ROUND(SUM(b.`total_taxes_and_charges`),2) AS \"Total Taxes and Charges\",\n ROUND(SUM(b.`grand_total`),2) AS \"Grand Total\",\n ROUND(SUM(b.`grand_total` - b.`rounded_total`),2) AS \"Round Off\",\n ROUND(SUM(b.`rounded_total` - b.`paid_amount` + b.`change_amount`), 2)AS \"Cash Discounts\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1 \n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n)\nGROUP BY \n date_list.`date`\nORDER BY \n date_list.`date` DESC", + "ref_doctype": "POS Invoice", + "report_name": "Daywise Sales", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/employee_sales/__init__.py b/ury_pulse/ury_pulse/report/employee_sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/employee_sales/employee_sales.json b/ury_pulse/ury_pulse/report/employee_sales/employee_sales.json new file mode 100644 index 0000000..8dd374c --- /dev/null +++ b/ury_pulse/ury_pulse/report/employee_sales/employee_sales.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2023-09-29 14:57:00.807965", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:54:06.088304", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Employee Sales", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT\n e.`full_name` AS \"Employee\",\n date_list.`date` AS \"Date\",\n COUNT(b.`name`) AS \"Total Invoices\",\n SUM(b.`grand_total`) AS \"Sales Amount\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1\n)\nINNER JOIN `tabUser` e ON(\n e.`name`= b.`waiter`\n)\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n)\nGROUP BY \n date_list.`date`,e.`full_name` \nORDER BY \n date_list.`date` DESC", + "ref_doctype": "POS Invoice", + "report_name": "Employee Sales", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/item_wise_sales/__init__.py b/ury_pulse/ury_pulse/report/item_wise_sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/item_wise_sales/item_wise_sales.json b/ury_pulse/ury_pulse/report/item_wise_sales/item_wise_sales.json new file mode 100644 index 0000000..3380fa8 --- /dev/null +++ b/ury_pulse/ury_pulse/report/item_wise_sales/item_wise_sales.json @@ -0,0 +1,58 @@ +{ + "add_total_row": 1, + "columns": [], + "creation": "2023-09-29 14:51:11.124653", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "options": "", + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:53:14.387186", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Item Wise Sales", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT \n c.`item_group` AS \"Item Group\",\n c.`item_name` AS \"Item Name\",\n SUM(b.`qty`) AS \"Qty\",\n SUM(b.`amount`) AS \"Amount\"\nFROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\nLEFT JOIN `tabPOS Invoice` a ON (\n a.`branch` = %(branch)s\n AND a.`status` IN (\"Consolidated\",\"Paid\") \n AND a.`docstatus` = 1 \n)\nINNER JOIN `tabPOS Invoice Item`b ON a.`name`=b.`parent`\nLEFT JOIN `tabItem` c ON c.`item_code` = b.`item_code`\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE\n(\n (rs.`hours` IS NULL AND a.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(a.`posting_date`, a.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(a.`posting_date`, a.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND a.`posting_date` = date_list.`date`)\n)\nGROUP BY \n c.`item_name`\nORDER BY \n c.`item_group` ASC, b.`item_name` ASC", + "ref_doctype": "POS Invoice", + "report_name": "Item Wise Sales", + "report_script": "", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/month_wise_sales/__init__.py b/ury_pulse/ury_pulse/report/month_wise_sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/month_wise_sales/month_wise_sales.json b/ury_pulse/ury_pulse/report/month_wise_sales/month_wise_sales.json new file mode 100644 index 0000000..c92b9e1 --- /dev/null +++ b/ury_pulse/ury_pulse/report/month_wise_sales/month_wise_sales.json @@ -0,0 +1,43 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2023-09-29 14:48:49.987205", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:52:20.045215", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Month Wise Sales", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT\n YEAR(daily_report.`Date`) AS \"YEAR\",\n MONTHNAME(daily_report.`Date`) AS \"MONTH\",\n ROUND(SUM(daily_report.`Item Total`), 2) AS \"Item Total\",\n ROUND(SUM(daily_report.`Total Taxes and Charges`),2) AS \"Total Taxes and Charges\",\n ROUND(SUM(daily_report.`Grand Total`), 2) AS \"Grand Total\"\nFROM \n (\n SELECT \n date_list.`date` AS \"Date\",\n ROUND(SUM(b.`net_total`),2) AS \"Item Total\",\n ROUND(SUM(b.`total_taxes_and_charges`),2) AS \"Total Taxes and Charges\",\n ROUND(SUM(b.`grand_total`),2) AS \"Grand Total\"\n FROM \n (\n SELECT DATE_SUB(DATE_FORMAT(CURDATE(), '%%Y-%%m-01'),INTERVAL 4 MONTH) AS `date`\n UNION\n SELECT DATE_ADD(DATE_SUB(DATE_FORMAT(CURDATE(), '%%Y-%%m-01'),INTERVAL 4 MONTH), INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(DATE_SUB(DATE_FORMAT(CURDATE(), '%%Y-%%m-01'),INTERVAL 4 MONTH), INTERVAL n DAY) <= CURDATE()\n ) AS date_list\n LEFT JOIN `tabPOS Invoice` b ON (\n b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\") \n AND b.`docstatus` = 1 \n )\n LEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n )\n WHERE\n (\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n )\n GROUP BY \n date_list.`date`\n ORDER BY \n date_list.`date` DESC\n ) AS daily_report\nGROUP BY\n YEAR(daily_report.`Date`),\n MONTH(daily_report.`Date`)\nORDER BY\n YEAR(daily_report.`Date`) DESC,\n MONTH(daily_report.`Date`) DESC;", + "ref_doctype": "POS Invoice", + "report_name": "Month Wise Sales", + "report_script": "", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/repeated_customers/__init__.py b/ury_pulse/ury_pulse/report/repeated_customers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/repeated_customers/repeated_customers.json b/ury_pulse/ury_pulse/report/repeated_customers/repeated_customers.json new file mode 100644 index 0000000..76faa84 --- /dev/null +++ b/ury_pulse/ury_pulse/report/repeated_customers/repeated_customers.json @@ -0,0 +1,56 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2023-09-29 14:52:16.514901", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "From Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "To Date", + "mandatory": 1, + "wildcard_filter": 0 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:53:47.198787", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Repeated Customers", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT\n `Date`,\n `Total Customers`,\n `New Customers`,\n `Total Customers`-`New Customers` AS `Repeated Customers`,\n ROUND(((`Total Customers`-`New Customers`) / `Total Customers`)*100,2) AS Percentage\nFROM\n (SELECT\n date_list.`date` AS `Date`,\n COUNT(d.customer) AS `Total Customers`,\n (SELECT\n COUNT(DISTINCT(a.`customer`))\n FROM `tabPOS Invoice`a\n INNER JOIN(SELECT DISTINCT(`customer`),`posting_date`,`posting_time`,`branch`,`naming_series`,`status`,`docstatus`,`customer_group` FROM\n `tabPOS Invoice`)b ON (\n b.`customer` != a.`customer`\n AND(\n (rs.`hours` IS NULL AND b.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = date_list.`date`)\n )\n AND b.`customer_group` != \"Aggregators\"\n AND b.`branch` = %(branch)s\n AND b.`status` IN (\"Consolidated\",\"Paid\")\n AND b.`docstatus` = 1)\n LEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = a.branch\n )\n WHERE\n a.`customer_group` != \"Aggregators\"\n AND(\n (rs.`hours` IS NULL AND a.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(a.`posting_date`, a.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(a.`posting_date`, a.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND a.`posting_date` = date_list.`date`)\n )\n AND a.`branch` = %(branch)s\n AND a.`status` IN (\"Consolidated\",\"Paid\") \n AND a.`docstatus` = 1) AS `New Customers`\n FROM \n (\n SELECT %(start_date)s AS `date`\n UNION\n SELECT DATE_ADD(%(start_date)s, INTERVAL n DAY) AS `date`\n FROM (\n SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n\n FROM (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS a\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS b\n CROSS JOIN (\n SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9\n ) AS c\n ORDER BY n\n ) AS nums\n WHERE DATE_ADD(%(start_date)s, INTERVAL n DAY) < %(end_date)s\n UNION\n SELECT %(end_date)s AS `date`\n ) AS date_list\n LEFT JOIN `tabPOS Invoice` d ON (\n d.`branch` = %(branch)s\n AND d.`status` IN (\"Consolidated\",\"Paid\") \n AND d.`docstatus` = 1\n )\n LEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n )\n WHERE\n (\n d.`customer_group` != \"Aggregators\"\n AND(\n (rs.`hours` IS NULL AND d.`posting_date` = date_list.`date`)\n OR (rs.`hours` > 0 AND TIMESTAMP(d.`posting_date`, d.`posting_time`) <= TIMESTAMP(DATE_ADD(date_list.`date`, INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(d.`posting_date`, d.`posting_time`) >= TIMESTAMP(date_list.`date`, CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND d.`posting_date` = date_list.`date`)\n )\n )\n GROUP BY \n date_list.`date`\n ORDER BY \n date_list.`date` DESC) AS subquery;", + "ref_doctype": "POS Invoice", + "report_name": "Repeated Customers", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/ury_pulse/report/today's_sales/__init__.py b/ury_pulse/ury_pulse/report/today's_sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ury_pulse/ury_pulse/report/today's_sales/today's_sales.json b/ury_pulse/ury_pulse/report/today's_sales/today's_sales.json new file mode 100644 index 0000000..7b7ff5f --- /dev/null +++ b/ury_pulse/ury_pulse/report/today's_sales/today's_sales.json @@ -0,0 +1,42 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2023-09-29 14:44:32.146055", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [ + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "mandatory": 1, + "options": "Branch", + "wildcard_filter": 0 + } + ], + "idx": 0, + "is_standard": "Yes", + "modified": "2023-10-25 17:51:35.457602", + "modified_by": "Administrator", + "module": "URY Pulse", + "name": "Today's Sales", + "owner": "Administrator", + "prepared_report": 0, + "query": "SELECT\n DAYNAME(curdate()) AS \"Today\",\n COUNT(b.`name`) AS \"Total Invoices\",\n SUM(b.`net_total`) AS \"Item Total\",\n SUM(b.`grand_total` - b.`net_total`) AS \"GST\",\n SUM(b.`grand_total`) AS \"Grand Total\",\n SUM(b.`grand_total` - b.`rounded_total`) AS \"Round Off\",\n SUM(b.`rounded_total` - b.`paid_amount` + b.`change_amount`) AS \"Cash Discounts\"\nFROM `tabPOS Invoice` b\nLEFT JOIN `tabReport Settings` rs ON (\n rs.`branch` = %(branch)s\n)\nWHERE \n b.`branch` = %(branch)s\n AND\n (\n (rs.`hours` IS NULL AND b.`posting_date` = curdate())\n OR (rs.`hours` > 0 AND TIMESTAMP(b.`posting_date`, b.`posting_time`) <= TIMESTAMP(DATE_ADD(curdate(), INTERVAL 1 DAY), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')) AND TIMESTAMP(b.`posting_date`, b.`posting_time`) >= TIMESTAMP(curdate(), CONCAT(LPAD(rs.`hours`, 2, '0'), ':00:00')))\n OR (rs.`branch` IS NULL AND b.`posting_date` = curdate())\n )\n AND b.`status` IN (\"Consolidated\", \"Paid\") \n AND b.`docstatus` = 1", + "ref_doctype": "POS Invoice", + "report_name": "Today's Sales", + "report_type": "Query Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + }, + { + "role": "URY Manager" + } + ] +} \ No newline at end of file diff --git a/ury_pulse/www/__init__.py b/ury_pulse/www/__init__.py new file mode 100644 index 0000000..e69de29