# DocType的类型

让我们通过创建更多的DocTypes来了解框架中不同类型的DocType。

# 图书馆会员资格

让我们创建另一个DocType:图书馆会员资格。它将包含以下字段:

  1. 图书馆成员(链接,必填)
  2. 全名(数据,只读)
  3. 起始日期(日期)
  4. 结束日期(日期)
  5. 已支付(勾选)

它将启用可提交。它的命名将设置为LMS.#####,并且限制为图书馆管理员角色。同时,在视图设置部分将标题字段设置为full_name

创建图书馆会员资格DocType

链接字段图书馆成员类似于其他框架中的外键列。它将允许您将值链接到另一个DocType中的记录。在这种情况下,它链接到图书馆成员DocType的记录。

全名字段是一个只读字段,它将自动从链接记录图书馆成员中的full_name字段获取

现在,转到图书馆会员资格列表并创建一个新文档。您将看到图书馆成员字段是一个下拉菜单,显示存在的记录作为选项。选择一个图书馆成员,全名将自动获取。很酷,对吧?

# 链接DocTypes

链接DocTypes是在其他DocTypes中作为链接字段链接的DocTypes。所有DocTypes都可以链接。我们可以根据它们存储的数据类型将DocTypes大致分类为主记录和交易记录。文章、图书馆成员是主记录数据的例子,因为它们代表一个实体(物理的或虚拟的)。图书馆会员资格是存储交易数据的DocType的一个例子。

# 可提交DocTypes

当您在DocType中启用可提交时,它就变成了一个可提交DocType。一个可提交DocType可以有3个状态:草稿已提交已取消。处于草稿状态的文档可以像任何文档一样更改,然而一旦它处于已提交状态,文档中任何字段的值都不能更改。一个已提交的文档可以取消,这会使文档无效。如果您注意到,我们的图书馆会员资格DocType中添加了一个额外的字段,称为修改自。这个字段用于跟踪文档中的修改。一旦文档被取消,它只能被修改,这意味着它可以被复制,并且已取消的文档将通过修改自字段链接到新的修改后的文档。

# 会员资格的控制器验证

现在,让我们编写代码,确保每当创建图书馆会员资格时,该成员没有有效的会员资格。

library_membership.py

import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus

class LibraryMembership(Document):
    # 在提交此文档之前进行检查
    def before_submit(self):
        exists = frappe.db.exists(
            "Library Membership",
            {
                "library_member": self.library_member,
                "docstatus": DocStatus.submitted(),
                # 检查会员资格的结束日期是否晚于此会员资格的开始日期
                "to_date": (">", self.from_date),
            },
        )
        if exists:
            frappe.throw("此成员已有有效的会员资格")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

我们在before_submit方法中编写了逻辑,该方法将在我们提交文档之前运行。我们使用了frappe.db.exists方法来检查是否存在具有我们提供的过滤器的图书馆会员资格记录。如果存在,我们使用了frappe.throw来停止程序的执行,并显示一条消息,让用户知道原因。

现在,尝试创建一个有重叠期限的图书馆会员资格,当您提交文档时应该会出现错误。

验证错误

# 图书馆交易

让我们创建一个DocType来记录一个拥有有效会员资格的图书馆成员发出或归还文章。

这个DocType将被称为图书馆交易,将包含以下字段:

  1. 文章 - 链接到文章
  2. 图书馆成员 - 链接到图书馆成员
  3. 类型 - 选择,有2个选项:发出和归还
  4. 日期 - 交易日期

这个DocType也将是一个可提交DocType。

创建图书馆交易DocType

# 交易验证

当发出一篇文章时,我们应该验证图书馆成员是否有有效的会员资格。我们还应该检查文章是否可供发出。让我们编写这些验证的代码。

library_transaction.py

import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus

class LibraryTransaction(Document):
    def before_submit(self):
        if self.type == "Issue":
            self.validate_issue()
            # 设置文章状态为已发出
            article = frappe.get_doc("Article", self.article)
            article.status = "Issued"
            article.save()

        elif self.type == "Return":
            self.validate_return()
            # 设置文章状态为可用
            article = frappe.get_doc("Article", self.article)
            article.status = "Available"
            article.save()

    def validate_issue(self):
        self.validate_membership()
        article = frappe.get_doc("Article", self.article)
        # 如果文章已经被发出,则不能发出
        if article.status == "Issued":
            frappe.throw("文章已被其他成员发出")

    def validate_return(self):
        article = frappe.get_doc("Article", self.article)
        # 如果文章尚未发出,则不能归还
        if article.status == "Available":
            frappe.throw("文章尚未发出,不能归还")

    def validate_membership(self):
        # 检查此图书馆成员是否有有效的会员资格
        valid_membership = frappe.db.exists(
            "Library Membership",
            {
                "library_member": self.library_member,
                "docstatus": DocStatus.submitted(),
                "from_date": ("<", self.date),
                "to_date": (">", self.date),
            },
        )
        if not valid_membership:
            frappe.throw("该成员没有有效的会员资格")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

这里有大量的代码,但它应该是自解释的。有内联代码注释以供更多解释。

# 图书馆设置

让我们为我们的应用程序创建最后一个DocType:图书馆设置。它将包含以下字段:

  1. 贷款期限 - 定义贷款期限的天数
  2. 最大发出文章数 - 限制单个成员可以发出的文章的最大数量

由于我们不需要为这些设置有多个记录,我们将为此DocType启用单一

创建图书馆设置DocType

创建好DocType后,点击转到图书馆设置,进入表单并设置贷款期限最大发出文章数的值。

# 单一DocTypes

当一个DocType启用单一时,它就变成了一个单一DocType。单一DocType类似于其他框架中的单例记录。它不会创建新的数据库表。相反,所有单一值都存储在单个表tabSingles中。它通常用于存储全局设置。

# 图书馆设置的验证

让我们对图书馆会员资格进行更改,使得结束日期根据贷款期限和开始日期自动计算。

library_membership.py

import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus

class LibraryMembership(Document):
    # 在提交此文档之前进行检查
    def before_submit(self):
        exists = frappe.db.exists(
            "Library Membership",
            {
                "library_member": self.library_member,
                "docstatus": DocStatus.submitted(),
                # 检查会员资格的结束日期是否晚于此会员资格的开始日期
                "to_date": (">", self.from_date),
            },
        )
        if exists:
            frappe.throw("此成员已有有效的会员资格")

        # 获取贷款期限,并通过给from_date添加loan_period来计算to_date
        loan_period = frappe.db.get_single_value("Library Settings", "loan_period")
        self.to_date = frappe.utils.add_days(self.from_date, loan_period or 30)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

我们使用了frappe.db.get_single_value方法来获取图书馆设置DocType中的loan_period值。

现在,让我们对图书馆交易进行更改,使得在发出文章时检查是否达到了最大限制。

library_transaction.py

import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus

class LibraryTransaction(Document):
    def before_submit(self):
        if self.type == "Issue":
            self.validate_issue()
            self.validate_maximum_limit()
            # 设置文章状态为已发出
            article = frappe.get_doc("Article", self.article)
            article.status = "Issued"
            article.save()

        elif self.type == "Return":
            self.validate_return()
            # 设置文章状态为可用
            article = frappe.get_doc("Article", self.article)
            article.status = "Available"
            article.save()

    def validate_issue(self):
        self.validate_membership()
        article = frappe.get_doc("Article", self.article)
        # 如果文章已经被发出,则不能发出
        if article.status == "Issued":
            frappe.throw("文章已被其他成员发出")

    def validate_return(self):
        article = frappe.get_doc("Article", self.article)
        # 如果文章尚未发出,则不能归还
        if article.status == "Available":
            frappe.throw("文章尚未发出,不能归还")

    def validate_maximum_limit(self):
        max_articles = frappe.db.get_single_value("Library Settings", "max_articles")
        count = frappe.db.count(
            "Library Transaction",
            {"library_member": self.library_member, "type": "Issue", "docstatus": DocStatus.submitted()},
        )
        if count >= max_articles:
            frappe.throw("发出文章的数量已达到最大限制")

    def validate_membership(self):
        # 检查此图书馆成员是否有有效的会员资格
        valid_membership = frappe.db.exists(
            "Library Membership",
            {
                "library_member": self.library_member,
                "docstatus": DocStatus.submitted(),
                "from_date": ("<", self.date),
                "to_date": (">", self.date),
            },
        )
        if not valid_membership:
            frappe.throw("该成员没有有效的会员资格")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

我们添加了一个validate_maximum_limit方法,并使用了frappe.db.count来计算成员进行的交易数量。

好了,我们已经涵盖了DocType创建的基础知识和DocType的类型。我们还为各种DocTypes编写了业务逻辑。

到目前为止做得很好。让我们继续。

接下来: 表单脚本.md

最后更新时间: 9/27/2024, 3:24:28 PM