Last active
March 27, 2024 18:29
-
-
Save MaxMorais/9ae255a7df742cff4d3adb58a0daea70 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import frappe | |
from frappe.model.document import Document | |
from frappe.utils.nestedset import NestedSet | |
from six import string_types | |
from frappe.utils import getdate, nowdate | |
status_map = {} | |
class SugaredDocument(Document): | |
def __init__(self, *args, **kwargs): | |
super(SugaredDocument, self).__init__(*args, **kwargs) | |
for link in self.meta.get_link_fields(): | |
super(SugaredDocument, self).__setattr__( | |
link.fieldname, | |
LinkDescriptor(link.options, link.fieldname, self.get(link.fieldname)) | |
) | |
for link in self.meta.get_dynamic_link_fields(): | |
super(SugaredDocument, self).__setattr__( | |
link.fieldname, | |
DynamicLinkDescriptor(link.options, link.fieldname, self.__dict__.get(link.fieldname)) | |
) | |
for vlink, dt in getattr(self, 'virtual_links', {}).items(): | |
super(SugaredDocument, self).__setattr__( | |
vlink, | |
DynamicLinkDescriptor(dt, vlink, self.__dict__.get(vlink)) | |
) | |
def set_status(self, update=False, status=None, update_modified=True): | |
if self.is_new(): | |
if self.get('amended_from'): | |
self.status = 'Draft' | |
return | |
if self.doctype in status_map: | |
_status = self.status | |
if status and update: | |
self.db_set("status", status) | |
sl = status_map[self.doctype][:] | |
sl.reverse() | |
s = [] | |
for s in sl: | |
if not s[1]: | |
self.status = s[0] | |
break | |
elif s[1].startswith("eval:"): | |
if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, | |
"nowdate": nowdate, "get_value": frappe.db.get_value , 'len': len}): | |
self.status = s[0] | |
break | |
elif getattr(self, s[1])(): | |
self.status = s[0] | |
break | |
if self.status != _status and len(s) > 2 and s[2]: | |
self.add_comment("Label", _(self.status)) | |
if update: | |
self.db_set('status', self.status, update_modified = update_modified) | |
def __getattribute__(self, name): | |
value = object.__getattribute__(self, name) | |
if hasattr(value, '__get__') and not callable(value): | |
value = value.__get__(self, self.__class__) | |
return value | |
def __setattribute__(self, name, value): | |
try: | |
obj = object.__getattribute__(self, name) | |
except AttributeError: | |
pass | |
else: | |
if hasattr(obj, '__set__'): | |
return obj.__set__(self, value) | |
return object.__setattr__(self, name, value) | |
__setattr__ = __setattribute__ | |
def get(self, key=None, filters=None, limit=None, default=None): | |
ret = super(SugaredDocument, self).get(key, filters, limit, default) | |
if isinstance(ret, (LinkDescriptor, DynamicLinkDescriptor)): | |
return ret.value | |
return ret | |
def set(self, key, value, as_value=False): | |
if isinstance(value, list) and not as_value: | |
self.__dict__[key] = [] | |
self.extend(key, value) | |
else: | |
obj = super(SugaredDocument, self).get(key) | |
if isinstance(obj, (LinkDescriptor, DynamicLinkDescriptor)): | |
setattr(self, key, value) | |
else: | |
self.__dict__[key] = value | |
def __eq__(self, other): | |
if isinstance(other, string_types) and not self.is_new(): | |
return self.name == other | |
elif isinstance(other, Document) and not other.is_new() and not self.is_new(): | |
return self.doctype == other.doctype and self.name == other.name | |
return False | |
def __ne__(self, other): | |
return not self.__eq__(other) | |
def __str__(self): | |
return self.name | |
def __unicode__(self): | |
return self.name | |
def truth(self): | |
return bool( | |
self.doctype and self.name \ | |
and frappe.db.exists(self.doctype, self.name)) | |
class SugaredNestedSet(NestedSet, SugaredDocument): | |
pass | |
class LinkDescriptor(object): | |
def __init__(self, doctype, fieldname, value=None): | |
self.doctype = doctype | |
self.fieldname = fieldname | |
self.value = value | |
self.__doc = None | |
def __get__(self, instance, owner): | |
if self.value is None: | |
return None | |
elif self.__doc is None: | |
self.__doc = frappe.get_doc(self.doctype, self.value) | |
return self.__doc | |
def __set__(self, instance, value): | |
self.value = value | |
if self.__doc: | |
self.__doc = None | |
class DynamicLinkDescriptor(object): | |
def __init__(self, reference, fieldname, value=None): | |
self.reference = reference | |
self.fieldname = fieldname | |
self.value = value | |
self.__doc = None | |
def __get__(self, instance, owner): | |
dt = instance.get(self.reference) | |
if not all([self.__doc, dt, self.value]): | |
return None | |
elif not self.__doc and all(dt, self.value): | |
self.__doc = frappe.get_doc(dt, self.value) | |
return self.__doc | |
def __set__(self, instance, value): | |
self.value = value | |
if self.__doc: | |
self.__doc = Nonee |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sugared_document import SugaredDocument | |
# Normal doctypes, childrens and singles | |
class MyClass(SugaredDocument): | |
pass | |
>>> doc = frappe.get_doc('MyClass', 'MyID') | |
>>> doc.link_field.name | |
'Something' | |
>>> doc.link_field.inner_field | |
'Else' | |
>>> doc.link_field.creation | |
datetime(2010, 1, 31, 12, 25, 35, 84526) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment