Skip to content

Commit 50e014f

Browse files
Merge branch 'develop' into bytes-fix
2 parents 4d48a2a + 3ba9c2d commit 50e014f

File tree

8 files changed

+76
-34
lines changed

8 files changed

+76
-34
lines changed

frappe/core/doctype/communication/communication.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,16 +351,26 @@ def get_contacts(email_strings):
351351
email = get_email_without_link(email)
352352
contact_name = get_contact_name(email)
353353

354-
if not contact_name:
355-
contact = frappe.get_doc({
356-
"doctype": "Contact",
357-
"first_name": frappe.unscrub(email.split("@")[0]),
358-
})
359-
contact.add_email(email_id=email, is_primary=True)
360-
contact.insert(ignore_permissions=True)
361-
contact_name = contact.name
362-
363-
contacts.append(contact_name)
354+
if not contact_name and email:
355+
email_parts = email.split("@")
356+
first_name = frappe.unscrub(email_parts[0])
357+
358+
try:
359+
contact_name = '{0}-{1}'.format(first_name, email_parts[1]) if first_name == 'Contact' else first_name
360+
contact = frappe.get_doc({
361+
"doctype": "Contact",
362+
"first_name": contact_name,
363+
"name": contact_name
364+
})
365+
contact.add_email(email_id=email, is_primary=True)
366+
contact.insert(ignore_permissions=True)
367+
contact_name = contact.name
368+
except Exception:
369+
traceback = frappe.get_traceback()
370+
frappe.log_error(traceback)
371+
372+
if contact_name:
373+
contacts.append(contact_name)
364374

365375
return contacts
366376

frappe/email/doctype/email_domain/email_domain.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import frappe
77
from frappe import _
88
from frappe.model.document import Document
9-
from frappe.utils import validate_email_address ,cint
9+
from frappe.utils import validate_email_address ,cint, cstr
1010
import imaplib,poplib,smtplib
1111
from frappe.email.utils import get_port
1212

@@ -51,7 +51,7 @@ def validate(self):
5151
try:
5252
if self.use_tls and not self.smtp_port:
5353
self.smtp_port = 587
54-
sess = smtplib.SMTP((self.smtp_server or "").encode('utf-8'), cint(self.smtp_port) or None)
54+
sess = smtplib.SMTP(cstr(self.smtp_server or ""), cint(self.smtp_port) or None)
5555
sess.quit()
5656
except Exception:
5757
frappe.throw(_("Outgoing email account not correct"))

frappe/email/smtp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import email.utils
99
import _socket, sys
1010
from frappe import _
11-
from frappe.utils import cint, parse_addr
11+
from frappe.utils import cint, cstr, parse_addr
1212

1313
def send(email, append_to=None, retry=1):
1414
"""Deprecated: Send the message or add it to Outbox Email"""
@@ -202,7 +202,7 @@ def sess(self):
202202
if self.use_tls and not self.port:
203203
self.port = 587
204204

205-
self._sess = smtplib.SMTP((self.server or "").encode('utf-8'),
205+
self._sess = smtplib.SMTP(cstr(self.server or ""),
206206
cint(self.port) or None)
207207

208208
if not self._sess:

frappe/model/workflow.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ def apply_workflow(doc, action):
105105

106106
return doc
107107

108+
@frappe.whitelist()
109+
def can_cancel_document(doc):
110+
doc = frappe.get_doc(frappe.parse_json(doc))
111+
workflow = get_workflow(doc.doctype)
112+
for state_doc in workflow.states:
113+
if state_doc.doc_status == '2':
114+
for transition in workflow.transitions:
115+
if transition.next_state == state_doc.state:
116+
return False
117+
return True
118+
return True
119+
108120
def validate_workflow(doc):
109121
'''Validate Workflow State and Transition for the current user.
110122

frappe/public/js/frappe/form/controls/time.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
4545
&& ((this.last_value && this.last_value !== this.value)
4646
|| (!this.datepicker.selectedDates.length))) {
4747

48-
var date_obj = frappe.datetime.moment_to_date_obj(moment(value, frappe.sys_defaults['time_format']));
48+
let time_format = frappe.sys_defaults.time_format || 'HH:mm:ss';
49+
var date_obj = frappe.datetime.moment_to_date_obj(moment(value, time_format));
4950
this.datepicker.selectDate(date_obj);
5051
}
5152
},

frappe/public/js/frappe/form/workflow.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,17 @@ frappe.ui.form.States = Class.extend({
105105
});
106106
}
107107
});
108-
this.setup_btn(added);
108+
if (!added) {
109+
//call function and clear cancel button if Cancel doc state is defined in the workfloe
110+
frappe.xcall('frappe.model.workflow.can_cancel_document', {doc: this.frm.doc}).then((can_cancel) => {
111+
if (!can_cancel) {
112+
this.frm.page.clear_secondary_action();
113+
}
114+
});
115+
} else {
116+
this.setup_btn(added);
117+
}
118+
109119
});
110120

111121
},

frappe/utils/pdf.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,24 @@
22
# MIT License. See license.txt
33
from __future__ import unicode_literals
44

5-
import pdfkit, os, frappe
5+
import io
6+
import os
7+
import re
68
from distutils.version import LooseVersion
7-
from frappe.utils import scrub_urls, get_wkhtmltopdf_version
8-
from frappe import _
9-
import six, re, io
9+
10+
import pdfkit
11+
import six
1012
from bs4 import BeautifulSoup
1113
from PyPDF2 import PdfFileReader, PdfFileWriter
1214

15+
import frappe
16+
from frappe import _
17+
from frappe.utils import get_wkhtmltopdf_version, scrub_urls
18+
19+
PDF_CONTENT_ERRORS = ["ContentNotFoundError", "ContentOperationNotPermittedError",
20+
"UnknownContentError", "RemoteHostClosedError"]
21+
22+
1323
def get_pdf(html, options=None, output=None):
1424
html = scrub_urls(html)
1525
html, options = prepare_options(html, options)
@@ -30,20 +40,14 @@ def get_pdf(html, options=None, output=None):
3040
# https://pythonhosted.org/PyPDF2/PdfFileReader.html
3141
# create in-memory binary streams from filedata and create a PdfFileReader object
3242
reader = PdfFileReader(io.BytesIO(filedata))
33-
34-
except IOError as e:
35-
if ("ContentNotFoundError" in e.message
36-
or "ContentOperationNotPermittedError" in e.message
37-
or "UnknownContentError" in e.message
38-
or "RemoteHostClosedError" in e.message):
43+
except OSError as e:
44+
if any([error in str(e) for error in PDF_CONTENT_ERRORS]):
45+
if not filedata:
46+
frappe.throw(_("PDF generation failed because of broken image links"))
3947

4048
# allow pdfs with missing images if file got created
41-
if filedata:
42-
if output: # output is a PdfFileWriter object
43-
output.appendPagesFromReader(reader)
44-
45-
else:
46-
frappe.throw(_("PDF generation failed because of broken image links"))
49+
if output: # output is a PdfFileWriter object
50+
output.appendPagesFromReader(reader)
4751
else:
4852
raise
4953

@@ -66,6 +70,7 @@ def get_pdf(html, options=None, output=None):
6670

6771
return filedata
6872

73+
6974
def get_file_data_from_writer(writer_obj):
7075

7176
# https://docs.python.org/3/library/io.html
@@ -112,6 +117,7 @@ def prepare_options(html, options):
112117

113118
return html, options
114119

120+
115121
def read_options_from_html(html):
116122
options = {}
117123
soup = BeautifulSoup(html, "html5lib")
@@ -132,6 +138,7 @@ def read_options_from_html(html):
132138

133139
return soup.prettify(), options
134140

141+
135142
def prepare_header_footer(soup):
136143
options = {}
137144

@@ -174,6 +181,7 @@ def prepare_header_footer(soup):
174181

175182
return options
176183

184+
177185
def cleanup(fname, options):
178186
if os.path.exists(fname):
179187
os.remove(fname)
@@ -182,6 +190,7 @@ def cleanup(fname, options):
182190
if options.get(key) and os.path.exists(options[key]):
183191
os.remove(options[key])
184192

193+
185194
def toggle_visible_pdf(soup):
186195
for tag in soup.find_all(attrs={"class": "visible-pdf"}):
187196
# remove visible-pdf class to unhide

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ passlib==1.7.1
3434
pdfkit==0.6.1
3535
Pillow==6.2.1
3636
premailer==3.6.1
37-
psycopg2-binary==2.7.5
38-
psycopg2==2.7.5
37+
psycopg2-binary==2.8.4
38+
psycopg2==2.8.4
3939
pyasn1==0.4.7
4040
Pygments==2.2.0
4141
PyJWT==1.7.1

0 commit comments

Comments
 (0)