From e108175ace49709a3dca23480c953f0ac2f84de3 Mon Sep 17 00:00:00 2001 From: Diksha Date: Tue, 14 May 2019 17:37:40 +0530 Subject: [PATCH 1/7] feat(core): request authorization --- .../doctype/authorization_request/__init__.py | 0 .../authorization_request.js | 7 + .../authorization_request.json | 528 ++++++++++++++++++ .../authorization_request.py | 31 + .../test_authorization_request.js | 23 + .../test_authorization_request.py | 10 + bloomstack_core/hooks.py | 3 +- bloomstack_core/public/js/quotation.js | 18 + .../emails/authorization_request.html | 1 + .../templates/includes/sign_document.js | 29 + bloomstack_core/utils.py | 16 + bloomstack_core/www/__init__.py | 0 bloomstack_core/www/authorize_document.html | 27 + bloomstack_core/www/authorize_document.py | 21 + 14 files changed, 713 insertions(+), 1 deletion(-) create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/__init__.py create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js create mode 100644 bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py create mode 100644 bloomstack_core/public/js/quotation.js create mode 100644 bloomstack_core/templates/emails/authorization_request.html create mode 100644 bloomstack_core/templates/includes/sign_document.js create mode 100644 bloomstack_core/www/__init__.py create mode 100644 bloomstack_core/www/authorize_document.html create mode 100644 bloomstack_core/www/authorize_document.py diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/__init__.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js new file mode 100644 index 000000000..c8edfae8f --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js @@ -0,0 +1,7 @@ +// Copyright (c) 2019, Bloom Stack, Inc and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Authorization Request", { + +}); +// frm.set_df_property("patient", "hidden", 0); diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json new file mode 100644 index 000000000..5acceb7ce --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -0,0 +1,528 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "AR.######", + "beta": 0, + "creation": "2019-05-10 04:18:42.975410", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 0, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "send_authorization_request", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Send Authorization Request", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "linked_doctype", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Linked DocType", + "length": 0, + "no_copy": 0, + "options": "DocType", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "linked_docname", + "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Linked DocName", + "length": 0, + "no_copy": 0, + "options": "linked_doctype", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fetch_if_empty": 0, + "fieldname": "authorizer_email", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Authorizer Email", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "cb", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "signature", + "fieldtype": "Signature", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Signature", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "signee_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Signee Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "section_break_4", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "token", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Token", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "token_generated_on", + "fieldtype": "Datetime", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Token Generated On", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "request_link", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Request Link", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "section_break_13", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 0, + "options": "Request Sent\nApproved\nRejected", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Authorization Request", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2019-05-21 07:06:38.393772", + "modified_by": "Administrator", + "module": "Bloomstack Core", + "name": "Authorization Request", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py new file mode 100644 index 000000000..dc89cf0c8 --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Bloom Stack, Inc and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from frappe.utils import getdate, now_datetime, nowdate + +class AuthorizationRequest(Document): + def on_submit(self): + self.generate_token() + self.email_link() + self.status = "Request Sent" + + def generate_token(self): + self.token = frappe.generate_hash(self.name, 32) + self.token_generated_on = now_datetime() + self.request_link = "http://localhost:8000/authorize_document?token={0}&name={1}".format(self.token, self.name) + + def email_link(self): + """ + Email the document link to user for them to authorize the document + """ + message = frappe.render_template("templates/emails/authorization_request.html", { + "authorization_request": self, + "link": self.request_link + }) + + frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) + frappe.msgprint("Document has been successfully sent to Email") diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js new file mode 100644 index 000000000..ec8cade49 --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Authorization Request", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Authorization Request + () => frappe.tests.make('Authorization Request', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py new file mode 100644 index 000000000..04f34047c --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Bloom Stack, Inc and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestAuthorizationRequest(unittest.TestCase): + pass diff --git a/bloomstack_core/hooks.py b/bloomstack_core/hooks.py index 4e523ebe0..4835e91a9 100755 --- a/bloomstack_core/hooks.py +++ b/bloomstack_core/hooks.py @@ -53,7 +53,8 @@ "Company": "public/js/company.js", "Supplier": "public/js/supplier.js", "Item": "public/js/item.js", - "Batch": "public/js/batch.js" + "Batch": "public/js/batch.js", + "Quotation": "public/js/quotation.js" } # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} diff --git a/bloomstack_core/public/js/quotation.js b/bloomstack_core/public/js/quotation.js new file mode 100644 index 000000000..21251f15a --- /dev/null +++ b/bloomstack_core/public/js/quotation.js @@ -0,0 +1,18 @@ +frappe.ui.form.on('Quotation', { + refresh: (frm) => { + if (!frm.is_new() && frm.doc.docstatus === 0) { + if (!frm.doc.customer_signature) { + frm.add_custom_button(__("Authorize"), () => { + frappe.new_doc("Authorization Request", { + linked_doctype: frm.doc.doctype, + linked_docname: frm.doc.name, + signee_name: frm.doc.contact_person, + authorizer_email: frm.doc.contact_email + }) + }).addClass("btn-primary"); + + } + } + }, + +}); diff --git a/bloomstack_core/templates/emails/authorization_request.html b/bloomstack_core/templates/emails/authorization_request.html new file mode 100644 index 000000000..f17f5fc5b --- /dev/null +++ b/bloomstack_core/templates/emails/authorization_request.html @@ -0,0 +1 @@ +

Hi, a document has been generated for you to authorize, please go here {{ link }}

\ No newline at end of file diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js new file mode 100644 index 000000000..544227cb2 --- /dev/null +++ b/bloomstack_core/templates/includes/sign_document.js @@ -0,0 +1,29 @@ +$(document).ready(function () { + var $sigdiv = $("#signature") + $sigdiv.jSignature(); + $sigdiv.jSignature("reset"); + + +$("#step2").on("click", function () { + var sign = $sigdiv.jSignature("getData"); + var signee = document.getElementById("signee").value; + if (!($sigdiv.jSignature('getData', 'native').length == 0) && signee) { + frappe.call({ + method: "bloomstack_core.utils.authorize_document", + args: { + sign: sign, + signee: signee, + docname: "{{ auth_req_docname }}", + }, + freeze: true, + callback: (r) => { + frappe.msgprint(__("The document has been approved by you!")); + } + }) + } + else{ + alert('Please enter Sign and Signee '); + } +}); + +}); \ No newline at end of file diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index d17ac3083..04b5a42a2 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -78,3 +78,19 @@ def log_request(endpoint, request_data, response, ref_dt=None, ref_dn=None): }) request.insert() frappe.db.commit() + +@frappe.whitelist() +def make_authorization_request(source_name, target_doc=None): + print(locals()) + +@frappe.whitelist(allow_guest=True) +def authorize_document(sign=None, signee=None, docname=None): + authorization_request = frappe.get_doc("Authorization Request", docname) + authorization_request.signature = sign + authorization_request.signee_name = signee + authorization_request.status = "Approved" + authorization_request.flags.ignore_permissions = True + authorization_request.save() + + authorized_doc = frappe.get_doc("Quotation", authorization_request.linked_docname) + authorized_doc.submit() diff --git a/bloomstack_core/www/__init__.py b/bloomstack_core/www/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bloomstack_core/www/authorize_document.html b/bloomstack_core/www/authorize_document.html new file mode 100644 index 000000000..351bf7038 --- /dev/null +++ b/bloomstack_core/www/authorize_document.html @@ -0,0 +1,27 @@ +{% extends "templates/web.html" %} +{% block title %} Authorize Document {% endblock %} + +{% block page_content %} +{% if error %} +{{ error }} +{% else %} +
+ +
+ {{ print_doc }} +
+ +
+ Signee name:
+
+ Sign document +
+ +
+{% endif %} +{% endblock %} + +{% block script %} + + +{% endblock %} \ No newline at end of file diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py new file mode 100644 index 000000000..f3c112e19 --- /dev/null +++ b/bloomstack_core/www/authorize_document.py @@ -0,0 +1,21 @@ +from __future__ import unicode_literals +import frappe + +no_cache = 1 + +def get_context(context): + token = frappe.local.request.args.get("token") + docname = frappe.local.request.args.get("name") + + auth_req = frappe.get_doc("Authorization Request", docname) + if not token or token == auth_req.token: + context.error = "Token is not valid. Click here to re-send email" + return + + if auth_req.status == "Approved": + context.error = "You have already authorized this document" + return + + frappe.local.flags.ignore_print_permissions = True + context.print_doc = frappe.get_print(auth_req.linked_doctype, auth_req.linked_docname) + context.auth_req_docname = docname \ No newline at end of file From 5553ab71f2da56562b65f173148800a7a4a6dfbd Mon Sep 17 00:00:00 2001 From: Diksha Date: Wed, 22 May 2019 20:23:42 +0530 Subject: [PATCH 2/7] feat(core): Request Authorization for Contract --- .../authorization_request.json | 4 ++-- bloomstack_core/hooks.py | 3 ++- bloomstack_core/public/js/contract.js | 15 +++++++++++++++ bloomstack_core/utils.py | 6 +++++- 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 bloomstack_core/public/js/contract.js diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json index 5acceb7ce..9bf884713 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -241,7 +241,7 @@ "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -489,7 +489,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-05-21 07:06:38.393772", + "modified": "2019-05-22 06:56:32.971310", "modified_by": "Administrator", "module": "Bloomstack Core", "name": "Authorization Request", diff --git a/bloomstack_core/hooks.py b/bloomstack_core/hooks.py index 4835e91a9..1759cf385 100755 --- a/bloomstack_core/hooks.py +++ b/bloomstack_core/hooks.py @@ -54,7 +54,8 @@ "Supplier": "public/js/supplier.js", "Item": "public/js/item.js", "Batch": "public/js/batch.js", - "Quotation": "public/js/quotation.js" + "Quotation": "public/js/quotation.js", + "Contract": "public/js/contract.js" } # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} diff --git a/bloomstack_core/public/js/contract.js b/bloomstack_core/public/js/contract.js new file mode 100644 index 000000000..29ebe5a54 --- /dev/null +++ b/bloomstack_core/public/js/contract.js @@ -0,0 +1,15 @@ +frappe.ui.form.on("Contract", { + refresh: (frm) => { + if (!frm.is_new() && frm.doc.docstatus === 0) { + if (!frm.doc.customer_signature) { + frm.add_custom_button(__("Authorize"), () => { + frappe.new_doc("Authorization Request", { + linked_doctype: frm.doc.doctype, + linked_docname: frm.doc.name, + }) + }).addClass("btn-primary"); + + } + } + }, +}); \ No newline at end of file diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index 04b5a42a2..0f7511707 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -92,5 +92,9 @@ def authorize_document(sign=None, signee=None, docname=None): authorization_request.flags.ignore_permissions = True authorization_request.save() - authorized_doc = frappe.get_doc("Quotation", authorization_request.linked_docname) + authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) + if authorized_doc.is_signed: + authorized_doc.is_signed =1 authorized_doc.submit() + + From 34f56ecb0d58f91f2b0cb1f7f4efcec89cc722f5 Mon Sep 17 00:00:00 2001 From: Diksha Date: Thu, 23 May 2019 17:40:02 +0530 Subject: [PATCH 3/7] req feat feat --- .../authorization_request.json | 6 +-- .../authorization_request.py | 6 +-- bloomstack_core/public/js/contract.js | 37 ++++++++++++++++-- bloomstack_core/public/js/quotation.js | 39 ++++++++++++++++--- bloomstack_core/utils.py | 20 ++++++++-- bloomstack_core/www/authorize_document.py | 1 + 6 files changed, 90 insertions(+), 19 deletions(-) diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json index 9bf884713..8bd4e7237 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -426,7 +426,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Status", "length": 0, @@ -485,11 +485,11 @@ "idx": 0, "image_view": 0, "in_create": 0, - "is_submittable": 1, + "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-05-22 06:56:32.971310", + "modified": "2019-05-23 03:14:25.832297", "modified_by": "Administrator", "module": "Bloomstack Core", "name": "Authorization Request", diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py index dc89cf0c8..970ff0f80 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -8,7 +8,7 @@ from frappe.utils import getdate, now_datetime, nowdate class AuthorizationRequest(Document): - def on_submit(self): + def after_insert(self): self.generate_token() self.email_link() self.status = "Request Sent" @@ -17,7 +17,8 @@ def generate_token(self): self.token = frappe.generate_hash(self.name, 32) self.token_generated_on = now_datetime() self.request_link = "http://localhost:8000/authorize_document?token={0}&name={1}".format(self.token, self.name) - + self.save() + def email_link(self): """ Email the document link to user for them to authorize the document @@ -28,4 +29,3 @@ def email_link(self): }) frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) - frappe.msgprint("Document has been successfully sent to Email") diff --git a/bloomstack_core/public/js/contract.js b/bloomstack_core/public/js/contract.js index 29ebe5a54..e40a40254 100644 --- a/bloomstack_core/public/js/contract.js +++ b/bloomstack_core/public/js/contract.js @@ -3,10 +3,39 @@ frappe.ui.form.on("Contract", { if (!frm.is_new() && frm.doc.docstatus === 0) { if (!frm.doc.customer_signature) { frm.add_custom_button(__("Authorize"), () => { - frappe.new_doc("Authorization Request", { - linked_doctype: frm.doc.doctype, - linked_docname: frm.doc.name, - }) + frappe.prompt([ + { + "label": "Contact Email", + "fieldtype": "Data", + "options": "Email", + "fieldname": "contact_email", + "default": frm.doc.contact_email, + "reqd": 1 + }, + { + "label": "Contact Person", + "fieldtype": "Data", + "fieldname": "contact_person", + "default": frm.doc.contact_person + } + ], + function (data) { + frappe.call({ + method: "bloomstack_core.utils.send_authorization_request", + args: { + dt: frm.doc.doctype, + dn: frm.doc.name, + contact_email: data.contact_email, + contact_name: data.contact_person + }, + callback: (r) => { + if (!r.exc) { + frappe.msgprint(__(`${frm.doc.name} has been successfully sent to ${data.contact_email}`)) + } + } + }) + }, + __("Send Authorization Request")) }).addClass("btn-primary"); } diff --git a/bloomstack_core/public/js/quotation.js b/bloomstack_core/public/js/quotation.js index 21251f15a..1bbb36345 100644 --- a/bloomstack_core/public/js/quotation.js +++ b/bloomstack_core/public/js/quotation.js @@ -3,12 +3,39 @@ frappe.ui.form.on('Quotation', { if (!frm.is_new() && frm.doc.docstatus === 0) { if (!frm.doc.customer_signature) { frm.add_custom_button(__("Authorize"), () => { - frappe.new_doc("Authorization Request", { - linked_doctype: frm.doc.doctype, - linked_docname: frm.doc.name, - signee_name: frm.doc.contact_person, - authorizer_email: frm.doc.contact_email - }) + frappe.prompt([ + { + "label": "Contact Email", + "fieldtype": "Data", + "options": "Email", + "fieldname": "contact_email", + "default": frm.doc.contact_email, + "reqd": 1 + }, + { + "label": "Contact Person", + "fieldtype": "Data", + "fieldname": "contact_person", + "default": frm.doc.contact_person + } + ], + function (data) { + frappe.call({ + method: "bloomstack_core.utils.send_authorization_request", + args: { + dt: frm.doc.doctype, + dn: frm.doc.name, + contact_email: data.contact_email, + contact_name: data.contact_person + }, + callback: (r) => { + if (!r.exc) { + frappe.msgprint(__(`${frm.doc.name} has been successfully sent to ${frm.doc.contact_email}`)) + } + } + }) + }, + __("Send Authorization Request")) }).addClass("btn-primary"); } diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index 0f7511707..807f597e0 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -93,8 +93,22 @@ def authorize_document(sign=None, signee=None, docname=None): authorization_request.save() authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) - if authorized_doc.is_signed: - authorized_doc.is_signed =1 - authorized_doc.submit() + try: + print("\n try \n") + if authorized_doc.is_signed: + authorized_doc.is_signed = 1 + except: + print("\n except \n") + authorized_doc.submit() +@frappe.whitelist() +def send_authorization_request(dt, dn, contact_email, contact_name=None): + print("lllllloooooocals", locals()) + print("Hellooooooooooooo") + new_authorization_request = frappe.new_doc("Authorization Request") + new_authorization_request.signee_name = contact_name + new_authorization_request.linked_doctype = dt + new_authorization_request.linked_docname = dn + new_authorization_request.authorizer_email = contact_email + new_authorization_request.save() \ No newline at end of file diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py index f3c112e19..23729584c 100644 --- a/bloomstack_core/www/authorize_document.py +++ b/bloomstack_core/www/authorize_document.py @@ -9,6 +9,7 @@ def get_context(context): auth_req = frappe.get_doc("Authorization Request", docname) if not token or token == auth_req.token: + print("token", token, "auth_req.token", auth_req.token) context.error = "Token is not valid. Click here to re-send email" return From 06394e58da1e4520cb542ae00f847e4b54599afa Mon Sep 17 00:00:00 2001 From: Diksha Date: Tue, 28 May 2019 15:15:12 +0530 Subject: [PATCH 4/7] feat(core): refactor code --- .../authorization_request.json | 35 +------------------ .../authorization_request.py | 13 +++---- bloomstack_core/public/js/contract.js | 6 ++-- bloomstack_core/public/js/quotation.js | 4 +-- .../templates/includes/sign_document.js | 1 + bloomstack_core/utils.py | 10 ++++-- bloomstack_core/www/authorize_document.html | 2 +- bloomstack_core/www/authorize_document.py | 2 +- 8 files changed, 23 insertions(+), 50 deletions(-) diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json index 8bd4e7237..06ff6e908 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -14,39 +14,6 @@ "editable_grid": 0, "engine": "InnoDB", "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "send_authorization_request", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Send Authorization Request", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -489,7 +456,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-05-23 03:14:25.832297", + "modified": "2019-05-28 02:15:38.316714", "modified_by": "Administrator", "module": "Bloomstack Core", "name": "Authorization Request", diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py index 970ff0f80..12042f0a9 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -10,22 +10,23 @@ class AuthorizationRequest(Document): def after_insert(self): self.generate_token() - self.email_link() + self.send_authorization_request() self.status = "Request Sent" def generate_token(self): self.token = frappe.generate_hash(self.name, 32) self.token_generated_on = now_datetime() - self.request_link = "http://localhost:8000/authorize_document?token={0}&name={1}".format(self.token, self.name) + self.request_link = "http://{0}/authorize_document?token={1}&name={2}".format(frappe.local.site, self.token, self.name) self.save() - def email_link(self): + def send_authorization_request(self): """ - Email the document link to user for them to authorize the document + Email the link to user for them to authorize the document """ + message = frappe.render_template("templates/emails/authorization_request.html", { - "authorization_request": self, - "link": self.request_link + "link": self.request_link, }) frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) + print("EMAIL SENT *****") \ No newline at end of file diff --git a/bloomstack_core/public/js/contract.js b/bloomstack_core/public/js/contract.js index e40a40254..fc124a25b 100644 --- a/bloomstack_core/public/js/contract.js +++ b/bloomstack_core/public/js/contract.js @@ -9,19 +9,19 @@ frappe.ui.form.on("Contract", { "fieldtype": "Data", "options": "Email", "fieldname": "contact_email", - "default": frm.doc.contact_email, + "default": frm.doc.party_user, "reqd": 1 }, { "label": "Contact Person", "fieldtype": "Data", "fieldname": "contact_person", - "default": frm.doc.contact_person + "default": frm.doc.party_name } ], function (data) { frappe.call({ - method: "bloomstack_core.utils.send_authorization_request", + method: "bloomstack_core.utils.create_authorization_request", args: { dt: frm.doc.doctype, dn: frm.doc.name, diff --git a/bloomstack_core/public/js/quotation.js b/bloomstack_core/public/js/quotation.js index 1bbb36345..bcae8f346 100644 --- a/bloomstack_core/public/js/quotation.js +++ b/bloomstack_core/public/js/quotation.js @@ -21,7 +21,7 @@ frappe.ui.form.on('Quotation', { ], function (data) { frappe.call({ - method: "bloomstack_core.utils.send_authorization_request", + method: "bloomstack_core.utils.create_authorization_request", args: { dt: frm.doc.doctype, dn: frm.doc.name, @@ -30,7 +30,7 @@ frappe.ui.form.on('Quotation', { }, callback: (r) => { if (!r.exc) { - frappe.msgprint(__(`${frm.doc.name} has been successfully sent to ${frm.doc.contact_email}`)) + frappe.msgprint(__(`The document ${frm.doc.name} has been successfully emailed to ${data.contact_person}`)) } } }) diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js index 544227cb2..f821c7fbf 100644 --- a/bloomstack_core/templates/includes/sign_document.js +++ b/bloomstack_core/templates/includes/sign_document.js @@ -8,6 +8,7 @@ $("#step2").on("click", function () { var sign = $sigdiv.jSignature("getData"); var signee = document.getElementById("signee").value; if (!($sigdiv.jSignature('getData', 'native').length == 0) && signee) { + $(".user-signature").hide(); frappe.call({ method: "bloomstack_core.utils.authorize_document", args: { diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index 807f597e0..1e1d9b866 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -95,15 +95,18 @@ def authorize_document(sign=None, signee=None, docname=None): authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) try: print("\n try \n") - if authorized_doc.is_signed: + if authorized_doc.is_signed == 0: authorized_doc.is_signed = 1 + authorized_doc.authorizer_signature = sign + authorized_doc.signee = signee + authorized_doc.submit() except: print("\n except \n") authorized_doc.submit() @frappe.whitelist() -def send_authorization_request(dt, dn, contact_email, contact_name=None): +def create_authorization_request(dt, dn, contact_email, contact_name=None): print("lllllloooooocals", locals()) print("Hellooooooooooooo") new_authorization_request = frappe.new_doc("Authorization Request") @@ -111,4 +114,5 @@ def send_authorization_request(dt, dn, contact_email, contact_name=None): new_authorization_request.linked_doctype = dt new_authorization_request.linked_docname = dn new_authorization_request.authorizer_email = contact_email - new_authorization_request.save() \ No newline at end of file + new_authorization_request.save() + print("GENERATED") \ No newline at end of file diff --git a/bloomstack_core/www/authorize_document.html b/bloomstack_core/www/authorize_document.html index 351bf7038..99f08f968 100644 --- a/bloomstack_core/www/authorize_document.html +++ b/bloomstack_core/www/authorize_document.html @@ -11,7 +11,7 @@ {{ print_doc }} -
+
Signee name:
Sign document diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py index 23729584c..e3c5ce857 100644 --- a/bloomstack_core/www/authorize_document.py +++ b/bloomstack_core/www/authorize_document.py @@ -8,7 +8,7 @@ def get_context(context): docname = frappe.local.request.args.get("name") auth_req = frappe.get_doc("Authorization Request", docname) - if not token or token == auth_req.token: + if not token or token != auth_req.token: print("token", token, "auth_req.token", auth_req.token) context.error = "Token is not valid. Click here to re-send email" return From ee5bf990315777185ba1d074ece0add2fa5890b6 Mon Sep 17 00:00:00 2001 From: Diksha Date: Tue, 28 May 2019 18:37:35 +0530 Subject: [PATCH 5/7] feat(core): remove print statements --- .../authorization_request.js | 1 - .../authorization_request.py | 3 +-- .../templates/includes/sign_document.js | 2 -- bloomstack_core/utils.py | 24 ++++++------------- bloomstack_core/www/authorize_document.py | 2 -- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js index c8edfae8f..657146f2b 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js @@ -4,4 +4,3 @@ frappe.ui.form.on("Authorization Request", { }); -// frm.set_df_property("patient", "hidden", 0); diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py index 12042f0a9..09f3e3a4e 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -28,5 +28,4 @@ def send_authorization_request(self): "link": self.request_link, }) - frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) - print("EMAIL SENT *****") \ No newline at end of file + frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) \ No newline at end of file diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js index f821c7fbf..6097c6d3c 100644 --- a/bloomstack_core/templates/includes/sign_document.js +++ b/bloomstack_core/templates/includes/sign_document.js @@ -3,7 +3,6 @@ $(document).ready(function () { $sigdiv.jSignature(); $sigdiv.jSignature("reset"); - $("#step2").on("click", function () { var sign = $sigdiv.jSignature("getData"); var signee = document.getElementById("signee").value; @@ -26,5 +25,4 @@ $("#step2").on("click", function () { alert('Please enter Sign and Signee '); } }); - }); \ No newline at end of file diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index 1e1d9b866..99456dfb9 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -79,10 +79,6 @@ def log_request(endpoint, request_data, response, ref_dt=None, ref_dn=None): request.insert() frappe.db.commit() -@frappe.whitelist() -def make_authorization_request(source_name, target_doc=None): - print(locals()) - @frappe.whitelist(allow_guest=True) def authorize_document(sign=None, signee=None, docname=None): authorization_request = frappe.get_doc("Authorization Request", docname) @@ -93,26 +89,20 @@ def authorize_document(sign=None, signee=None, docname=None): authorization_request.save() authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) - try: - print("\n try \n") - if authorized_doc.is_signed == 0: - authorized_doc.is_signed = 1 - authorized_doc.authorizer_signature = sign - authorized_doc.signee = signee - authorized_doc.submit() - except: - print("\n except \n") + if hasattr(authorized_doc, "is_signed"): + authorized_doc.is_signed = 1 + authorized_doc.authorizer_signature = sign + authorized_doc.signee = signee + authorized_doc.submit() + else: authorized_doc.submit() @frappe.whitelist() def create_authorization_request(dt, dn, contact_email, contact_name=None): - print("lllllloooooocals", locals()) - print("Hellooooooooooooo") new_authorization_request = frappe.new_doc("Authorization Request") new_authorization_request.signee_name = contact_name new_authorization_request.linked_doctype = dt new_authorization_request.linked_docname = dn new_authorization_request.authorizer_email = contact_email - new_authorization_request.save() - print("GENERATED") \ No newline at end of file + new_authorization_request.save() \ No newline at end of file diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py index e3c5ce857..e65a0ebf9 100644 --- a/bloomstack_core/www/authorize_document.py +++ b/bloomstack_core/www/authorize_document.py @@ -6,10 +6,8 @@ def get_context(context): token = frappe.local.request.args.get("token") docname = frappe.local.request.args.get("name") - auth_req = frappe.get_doc("Authorization Request", docname) if not token or token != auth_req.token: - print("token", token, "auth_req.token", auth_req.token) context.error = "Token is not valid. Click here to re-send email" return From 5f28e117102a7114928a2eda6e0b35ead15cd430 Mon Sep 17 00:00:00 2001 From: Diksha Date: Fri, 31 May 2019 17:23:22 +0530 Subject: [PATCH 6/7] fix(core): add reject document button, improve email body --- .../authorization_request.json | 6 +- .../authorization_request.py | 16 +- .../emails/authorization_request.html | 972 +++++++++++++++++- .../templates/includes/sign_document.js | 46 +- bloomstack_core/utils.py | 39 +- bloomstack_core/www/authorize_document.html | 12 +- bloomstack_core/www/authorize_document.py | 13 +- 7 files changed, 1054 insertions(+), 50 deletions(-) diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json index 06ff6e908..c1df7f9b7 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -393,7 +393,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, "label": "Status", "length": 0, @@ -452,11 +452,11 @@ "idx": 0, "image_view": 0, "in_create": 0, - "is_submittable": 0, + "is_submittable": 1, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-05-28 02:15:38.316714", + "modified": "2019-06-06 03:26:19.653725", "modified_by": "Administrator", "module": "Bloomstack Core", "name": "Authorization Request", diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py index 09f3e3a4e..d212bc693 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -5,7 +5,9 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document -from frappe.utils import getdate, now_datetime, nowdate +from frappe.utils import now_datetime +from frappe.utils.data import get_url +from erpnext import get_default_company class AuthorizationRequest(Document): def after_insert(self): @@ -16,16 +18,20 @@ def after_insert(self): def generate_token(self): self.token = frappe.generate_hash(self.name, 32) self.token_generated_on = now_datetime() - self.request_link = "http://{0}/authorize_document?token={1}&name={2}".format(frappe.local.site, self.token, self.name) + self.request_link = "{0}/authorize_document?token={1}&name={2}".format(get_url(), self.token, self.name) self.save() - + def send_authorization_request(self): """ Email the link to user for them to authorize the document """ + doc = frappe.get_doc(self.linked_doctype, self.linked_docname) + company = get_default_company() + + subject = "{0} requests your authorization on {1}".format(doc.company if doc.company else company, self.linked_doctype) message = frappe.render_template("templates/emails/authorization_request.html", { - "link": self.request_link, + "authorization_request": self, }) - frappe.sendmail(recipients=[self.authorizer_email], subject="You have a document to authorize", message=message) \ No newline at end of file + frappe.sendmail(recipients=[self.authorizer_email], subject=subject, message=message) \ No newline at end of file diff --git a/bloomstack_core/templates/emails/authorization_request.html b/bloomstack_core/templates/emails/authorization_request.html index f17f5fc5b..cc97a5d61 100644 --- a/bloomstack_core/templates/emails/authorization_request.html +++ b/bloomstack_core/templates/emails/authorization_request.html @@ -1 +1,971 @@ -

Hi, a document has been generated for you to authorize, please go here {{ link }}

\ No newline at end of file + + + + + + + + + *|MC:SUBJECT|* + + + + + + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+
+ +
+ + + + + +
+ + + + + +
+ + + + + + + + +
+ +

Authorization Request

+ +
+ + + +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + +
+ +
+You are requested to authorize a document.

+
+ + + +
+ + + + + +
+ + + + + + +

+ View Document +
+
+ + + + + +
+ + + + + + + + +
+ + Happy Blooming!
+Bloom Bot
+
+PS: This is an auto-generated email. If you'd like any technical support, please send an email to my humans - support@bloomstack.com +
+ + + +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + +
+ +
+ +
+ +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + +
+
+
+ +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + +
+ + Copyright ©2019 Bloomstack Inc, All rights reserved.
+
+Our mailing address is:
+support@bloomstack.com
+
+  +
+ + + +
+ +
+ +
+
+ + diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js index 6097c6d3c..7a3922d2b 100644 --- a/bloomstack_core/templates/includes/sign_document.js +++ b/bloomstack_core/templates/includes/sign_document.js @@ -1,28 +1,42 @@ $(document).ready(function () { var $sigdiv = $("#signature") - $sigdiv.jSignature(); - $sigdiv.jSignature("reset"); + $sigdiv.jSignature(); // inits the jSignature widget. + $sigdiv.jSignature("reset"); // clears the canvas and rerenders the decor on it. -$("#step2").on("click", function () { - var sign = $sigdiv.jSignature("getData"); - var signee = document.getElementById("signee").value; - if (!($sigdiv.jSignature('getData', 'native').length == 0) && signee) { + $("#approveDocument").on("click", function () { + var sign = $sigdiv.jSignature("getData"); + var signee = $("#signee").value; + if (!($sigdiv.jSignature('getData', 'native').length == 0) && signee) { // proceed only if user has put signature and signee name. + $(".user-signature").hide(); + frappe.call({ + method: "bloomstack_core.utils.authorize_document", + args: { + sign: sign, + signee: signee, + docname: "{{ auth_req_docname }}", + }, + freeze: true, + callback: (r) => { + frappe.msgprint(__("The document has been approved by you!")); + } + }) + } + else { + frappe.throw(__("Please put your name and signature!")); + } + }); + + $("#rejectDocument").on("click", function () { $(".user-signature").hide(); frappe.call({ - method: "bloomstack_core.utils.authorize_document", + method: "bloomstack_core.utils.reject_document", args: { - sign: sign, - signee: signee, docname: "{{ auth_req_docname }}", - }, + }, freeze: true, callback: (r) => { - frappe.msgprint(__("The document has been approved by you!")); + frappe.msgprint(__("The document has been rejected by you!")); } }) - } - else{ - alert('Please enter Sign and Signee '); - } -}); + }); }); \ No newline at end of file diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index 99456dfb9..8f971af7b 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -79,29 +79,38 @@ def log_request(endpoint, request_data, response, ref_dt=None, ref_dn=None): request.insert() frappe.db.commit() + @frappe.whitelist(allow_guest=True) def authorize_document(sign=None, signee=None, docname=None): - authorization_request = frappe.get_doc("Authorization Request", docname) - authorization_request.signature = sign - authorization_request.signee_name = signee - authorization_request.status = "Approved" - authorization_request.flags.ignore_permissions = True - authorization_request.save() - - authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) - if hasattr(authorized_doc, "is_signed"): - authorized_doc.is_signed = 1 - authorized_doc.authorizer_signature = sign - authorized_doc.signee = signee - authorized_doc.submit() - else: + if frappe.db.exists("Authorization Request", docname): + authorization_request = frappe.get_doc("Authorization Request", docname) + authorization_request.signature = sign + authorization_request.signee_name = signee + authorization_request.status = "Approved" + authorization_request.flags.ignore_permissions = True + authorization_request.save() + + authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) + if hasattr(authorized_doc, "is_signed") and hasattr(authorized_doc, "authorizer_signature") and hasattr(authorized_doc, "signee"): + if authorized_doc.is_signed == 0: + authorized_doc.is_signed = 1 + authorized_doc.authorizer_signature = sign + authorized_doc.signee = signee + authorized_doc.submit() +@frappe.whitelist(allow_guest=True) +def reject_document(docname): + if frappe.db.exists("Authorization Request", docname): + authorization_request = frappe.get_doc("Authorization Request", docname) + authorization_request.status = "Rejected" + authorization_request.save() + + @frappe.whitelist() def create_authorization_request(dt, dn, contact_email, contact_name=None): new_authorization_request = frappe.new_doc("Authorization Request") - new_authorization_request.signee_name = contact_name new_authorization_request.linked_doctype = dt new_authorization_request.linked_docname = dn new_authorization_request.authorizer_email = contact_email diff --git a/bloomstack_core/www/authorize_document.html b/bloomstack_core/www/authorize_document.html index 99f08f968..fcd85656b 100644 --- a/bloomstack_core/www/authorize_document.html +++ b/bloomstack_core/www/authorize_document.html @@ -7,14 +7,16 @@ {% else %}
-
+
{{ print_doc }}
-
- Signee name:
-
- Sign document +
+ Your Name:


+ Signature: +



+ Approve     + Reject
diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py index e65a0ebf9..a5bf2ca74 100644 --- a/bloomstack_core/www/authorize_document.py +++ b/bloomstack_core/www/authorize_document.py @@ -3,18 +3,21 @@ no_cache = 1 + def get_context(context): token = frappe.local.request.args.get("token") docname = frappe.local.request.args.get("name") auth_req = frappe.get_doc("Authorization Request", docname) + if not token or token != auth_req.token: context.error = "Token is not valid. Click here to re-send email" - return - if auth_req.status == "Approved": - context.error = "You have already authorized this document" - return + elif auth_req.status == "Approved": + context.error = "This document has already been authorized by you!" + + elif auth_req.status == "Rejected": + context.error = "This document has already been rejected by you!" frappe.local.flags.ignore_print_permissions = True context.print_doc = frappe.get_print(auth_req.linked_doctype, auth_req.linked_docname) - context.auth_req_docname = docname \ No newline at end of file + context.auth_req_docname = docname From 59ad65d8102d615cd519150261cb27d56a96464b Mon Sep 17 00:00:00 2001 From: diksha Date: Fri, 21 Jun 2019 12:40:51 +0530 Subject: [PATCH 7/7] feat(core): improve web view of request authorization --- .../authorization_request.py | 4 +- .../templates/includes/sign_document.js | 9 +- bloomstack_core/www/authorize_document.html | 241 +++++++++++++++++- bloomstack_core/www/authorize_document.py | 8 +- 4 files changed, 249 insertions(+), 13 deletions(-) diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py index d212bc693..eef97cb8d 100644 --- a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -27,9 +27,9 @@ def send_authorization_request(self): """ doc = frappe.get_doc(self.linked_doctype, self.linked_docname) - company = get_default_company() + company = doc.company if hasattr(doc, 'company') else get_default_company() - subject = "{0} requests your authorization on {1}".format(doc.company if doc.company else company, self.linked_doctype) + subject = "{0} requests your authorization on {1}".format(company, self.linked_doctype) message = frappe.render_template("templates/emails/authorization_request.html", { "authorization_request": self, }) diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js index 7a3922d2b..425a9d207 100644 --- a/bloomstack_core/templates/includes/sign_document.js +++ b/bloomstack_core/templates/includes/sign_document.js @@ -1,12 +1,12 @@ $(document).ready(function () { - var $sigdiv = $("#signature") + var $sigdiv = $("#signature"); $sigdiv.jSignature(); // inits the jSignature widget. $sigdiv.jSignature("reset"); // clears the canvas and rerenders the decor on it. $("#approveDocument").on("click", function () { var sign = $sigdiv.jSignature("getData"); - var signee = $("#signee").value; - if (!($sigdiv.jSignature('getData', 'native').length == 0) && signee) { // proceed only if user has put signature and signee name. + var signee = $("#signee").val(); + if ($sigdiv.jSignature('getData', 'native').length != 0 && signee) { // proceed only if user has put signature and signee name. $(".user-signature").hide(); frappe.call({ method: "bloomstack_core.utils.authorize_document", @@ -19,9 +19,10 @@ $(document).ready(function () { callback: (r) => { frappe.msgprint(__("The document has been approved by you!")); } - }) + }); } else { + frappe.throw(__("Please put your name and signature!")); } }); diff --git a/bloomstack_core/www/authorize_document.html b/bloomstack_core/www/authorize_document.html index fcd85656b..fb85bea75 100644 --- a/bloomstack_core/www/authorize_document.html +++ b/bloomstack_core/www/authorize_document.html @@ -1,22 +1,253 @@ {% extends "templates/web.html" %} {% block title %} Authorize Document {% endblock %} +{% block style %} + +{% endblock %} {% block page_content %} {% if error %} {{ error }} {% else %}
+
+

{{company}} has requested you to authorize a {{doc.doctype}}


+
+
-
- {{ print_doc }} +
+
+ {{ print_doc }}
+
+
- Your Name:


+ Your Name:

+


Signature:



- Approve     - Reject +
+ Approve + Reject +
diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py index a5bf2ca74..0a0c091af 100644 --- a/bloomstack_core/www/authorize_document.py +++ b/bloomstack_core/www/authorize_document.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals +from erpnext import get_default_company import frappe - +import re no_cache = 1 @@ -19,5 +20,8 @@ def get_context(context): context.error = "This document has already been rejected by you!" frappe.local.flags.ignore_print_permissions = True - context.print_doc = frappe.get_print(auth_req.linked_doctype, auth_req.linked_docname) + print_doc = frappe.get_print(auth_req.linked_doctype, auth_req.linked_docname) + context.print_doc = print_doc[print_doc.find('')+len(''):len(print_doc)-len('')] + context.doc = frappe.get_doc(auth_req.linked_doctype, auth_req.linked_docname) + context.company = context.doc.company if hasattr(context.doc, 'company') else get_default_company() context.auth_req_docname = docname