瀏覽代碼

#478

version-14
Rushabh Mehta 11 年之前
父節點
當前提交
a47da023c9
共有 3 個文件被更改,包括 84 次插入45 次删除
  1. +3
    -1
      frappe/exceptions.py
  2. +65
    -42
      frappe/model/document.py
  3. +16
    -2
      frappe/tests/test_document.py

+ 3
- 1
frappe/exceptions.py 查看文件

@@ -34,4 +34,6 @@ class MandatoryError(ValidationError): pass
class InvalidSignatureError(ValidationError): pass
class RateLimitExceededError(ValidationError): pass
class CannotChangeConstantError(ValidationError): pass
class LinkValidationError(ValidationError): pass
class LinkValidationError(ValidationError): pass
class DocstatusTransitionError(ValidationError): pass
class TimestampMismatchError(ValidationError): pass

+ 65
- 42
frappe/model/document.py 查看文件

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe.utils import cint, flt
from frappe.utils import cint, flt, cstr, now
from frappe.model import default_fields
from frappe.model.db_schema import type_map
from frappe.model.naming import set_new_name
@@ -98,11 +98,7 @@ class BaseDocument(object):
for fieldname in self.valid_columns:
d[fieldname] = self.get(fieldname)
return d
def get_for_save(self):
d = self.get_valid_dict()
@property
def valid_columns(self):
return self.get_valid_columns()
@@ -250,7 +246,8 @@ class Document(BaseDocument):
# check links
# check permissions
self.set_defaults()
self._set_defaults()
self._set_docstatus_user_and_timestamp()
self._validate()
# run validate, on update etc.
@@ -271,6 +268,7 @@ class Document(BaseDocument):
self.insert()
return

self._set_docstatus_user_and_timestamp()
self._validate()

# parent
@@ -285,14 +283,33 @@ class Document(BaseDocument):
d.db_update()
def update_single(self, d):
frappe.db.sql("""delete from tabSingles where doctype=%s""", d.get("doctype"))
frappe.db.sql("""delete from tabSingles where doctype=%s""", self.doctype)
for field, value in d.iteritems():
if field not in ("doctype"):
frappe.db.sql("""insert into tabSingles(doctype, field, value)
values (%s, %s, %s)""", (d.get("doctype", field, value)))
values (%s, %s, %s)""", (self.doctype, field, value))

def _set_docstatus_user_and_timestamp(self):
self._original_modified = self.modified
self.modified = now()
self.modified_by = frappe.session.user
if not self.creation:
self.creation = self.modified
if not self.owner:
self.owner = self.modified_by
if self.docstatus==None:
self.docstatus=0
for d in self.get_all_children():
d.docstatus = self.docstatus
d.modified = self.modified
d.modified_by = self.modified_by
if not d.owner:
d.owner = self.owner
if not d.creation:
d.creation = self.creation
def set_defaults(self):
def _set_defaults(self):
if frappe.flags.in_import:
return
@@ -308,60 +325,66 @@ class Document(BaseDocument):
d.set_missing_values(new_doc)

def _validate(self):
#self.check_if_latest()
self.check_if_latest()
self.validate_mandatory()
self.validate_links()
# check restrictions
def check_if_latest(self, method="save"):
def check_if_latest(self):
conflict = False
if not self.get('__islocal'):
if self.meta.issingle:
modified = frappe.db.get_value(self.doctype, self.name, "modified")
if cstr(modified) and cstr(modified) != cstr(self.modified):
if cstr(modified) and cstr(modified) != cstr(self._original_modified):
conflict = True
else:
tmp = frappe.db.sql("""select modified, docstatus from `tab%s`
where name=%s for update"""
% (self.doctype, '%s'), self.name, as_dict=True)
tmp = frappe.db.get_value(self.doctype, self.name,
["modified", "docstatus"], as_dict=True)

if not tmp:
frappe.msgprint("""This record does not exist. Please refresh.""", raise_exception=1)

modified = cstr(tmp[0].modified)
if modified and modified != cstr(self.modified):
modified = cstr(tmp.modified)
if modified and modified != cstr(self._original_modified):
conflict = True
self.check_docstatus_transition(tmp[0].docstatus, method)
self.check_docstatus_transition(tmp.docstatus)
if conflict:
frappe.msgprint(_("Error: Document has been modified after you have opened it") \
+ (" (%s, %s). " % (modified, self.modified)) \
+ _("Please refresh to get the latest document."), raise_exception=TimestampMismatchError)

def check_docstatus_transition(self, db_docstatus):
valid = {
"save": [0,0],
"submit": [0,1],
"cancel": [1,2],
"update_after_submit": [1,1]
}
labels = {
0: _("Draft"),
1: _("Submitted"),
2: _("Cancelled")
}
if not hasattr(self, "to_docstatus"):
self.to_docstatus = 0
if [db_docstatus, self.to_docstatus] != valid[method]:
frappe.msgprint(_("Cannot change from") + ": " + labels[db_docstatus] + " > " + \
labels[self.to_docstatus], raise_exception=DocstatusTransitionError)
+ _("Please refresh to get the latest document."),
raise_exception=frappe.TimestampMismatchError)

def check_docstatus_transition(self, docstatus):
if not self.docstatus:
self.docstatus = 0
if docstatus==0:
if self.docstatus==0:
self._action = "save"
elif self.docstatus==1:
self._action = "submit"
else:
raise frappe.DocstatusTransitionError
elif docstatus==1:
if self.docstatus==1:
self._action = "update_after_submit"
self.validate_update_after_submit()
elif self.docstatus==2:
self._action = "cancel"
else:
raise frappe.DocstatusTransitionError
elif docstatus==2:
raise frappe.ValidationError
def validate_update_after_submit(self):
# check only allowed values are updated
pass
def validate_mandatory(self):
if self.get("ignore_mandatory"):
return


+ 16
- 2
frappe/tests/test_document.py 查看文件

@@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

import frappe, unittest
import frappe, unittest, time

from frappe.model.document import Document

@@ -74,7 +74,21 @@ class TestDocument(unittest.TestCase):
d.set("first_name", "Test Mandatory")
d.insert()
self.assertEquals(frappe.db.get_value("User", d.name), d.name)
def test_confict_validation(self):
d1 = self.test_insert()
d2 = Document(d1.doctype, d1.name)
time.sleep(1)
d1.save()
self.assertRaises(frappe.TimestampMismatchError, d2.save)

def test_confict_validation_single(self):
d1 = Document("Website Settings", "Website Settings")
d2 = Document("Website Settings", "Website Settings")
time.sleep(1)
d1.save()
self.assertRaises(frappe.TimestampMismatchError, d2.save)
def test_link_validation(self):
d = Document({
"doctype": "User",


Loading…
取消
儲存