parties.typ 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // ==========================================
  2. // DOMAIN: СТОРОНЫ, АДРЕСАТЫ И ПОДПИСАНТЫ
  3. // ==========================================
  4. #import "document.typ": fail, ensure-dictionary
  5. #let normalize-text(value, scope, required: false) = {
  6. if value == none {
  7. if required { fail(scope, "поле обязательно") }
  8. none
  9. } else if type(value) != str {
  10. fail(scope, "ожидалась строка")
  11. } else if value.trim() == "" {
  12. if required { fail(scope, "поле не может быть пустым") }
  13. none
  14. } else {
  15. value
  16. }
  17. }
  18. #let signer(
  19. name,
  20. title,
  21. basis: none,
  22. signature: none,
  23. stamp: none,
  24. ) = {
  25. for (key, resource) in (("signature", signature), ("stamp", stamp)) {
  26. if resource != none and type(resource) not in (path, content) {
  27. fail("signer." + key, "ожидались none, path или content")
  28. }
  29. }
  30. (
  31. kind: "signer",
  32. name: normalize-text(name, "signer.name", required: true),
  33. title: normalize-text(title, "signer.title", required: true),
  34. basis: normalize-text(basis, "signer.basis"),
  35. signature: signature,
  36. stamp: stamp,
  37. )
  38. }
  39. #let recipient(
  40. company: none,
  41. title: none,
  42. name: none,
  43. address: none,
  44. ) = {
  45. let resolved = (
  46. kind: "recipient",
  47. company: normalize-text(company, "recipient.company"),
  48. title: normalize-text(title, "recipient.title"),
  49. name: normalize-text(name, "recipient.name"),
  50. address: normalize-text(address, "recipient.address"),
  51. )
  52. if resolved.company == none and resolved.name == none {
  53. fail("recipient", "нужно указать организацию или имя адресата")
  54. }
  55. resolved
  56. }
  57. #let party(
  58. id,
  59. role,
  60. name,
  61. legal: (:),
  62. contacts: (:),
  63. banking: (:),
  64. representative: none,
  65. ) = {
  66. if representative != none and (
  67. type(representative) != dictionary
  68. or representative.at("kind", default: none) != "signer"
  69. ) {
  70. fail("party.representative", "ожидались none или signer")
  71. }
  72. (
  73. kind: "party",
  74. id: normalize-text(id, "party.id", required: true),
  75. role: normalize-text(role, "party.role", required: true),
  76. name: normalize-text(name, "party.name", required: true),
  77. legal: ensure-dictionary(legal, "party.legal"),
  78. contacts: ensure-dictionary(contacts, "party.contacts"),
  79. banking: ensure-dictionary(banking, "party.banking"),
  80. representative: representative,
  81. )
  82. }
  83. #let approval(signer, date: none, label: "УТВЕРЖДАЮ") = {
  84. if type(signer) != dictionary or signer.at("kind", default: none) != "signer" {
  85. fail("approval.signer", "ожидался signer")
  86. }
  87. (
  88. kind: "approval",
  89. signer: signer,
  90. date: normalize-text(date, "approval.date"),
  91. label: normalize-text(label, "approval.label", required: true),
  92. )
  93. }
  94. #let validate-parties(parties, minimum: 0) = {
  95. if type(parties) != array {
  96. fail("parties", "ожидался array")
  97. }
  98. if parties.len() < minimum {
  99. fail("parties", "нужно не менее " + str(minimum) + " сторон")
  100. }
  101. let seen = ()
  102. for item in parties {
  103. if type(item) != dictionary or item.at("kind", default: none) != "party" {
  104. fail("parties", "каждый элемент должен быть party")
  105. }
  106. if item.id in seen {
  107. fail("parties", "повторяющийся id " + repr(item.id))
  108. }
  109. if item.representative != none and (
  110. type(item.representative) != dictionary
  111. or item.representative.at("kind", default: none) != "signer"
  112. ) {
  113. fail("parties", "representative должен быть signer")
  114. }
  115. seen.push(item.id)
  116. }
  117. parties
  118. }