Contacts
The Contacts module keeps the customers, the vendors and the vendor categories of a business. They are Orchard Core content types, so the content list, search, bulk actions, per-type permissions and content deployment come with them. The address and phone numbers are CrestApps content fields.
| Projects | CrestApps.Almohaseb.Contacts (module), CrestApps.Almohaseb.Contacts.Core (parts, indexes, rules, directory) |
| Feature | CrestApps.Almohaseb.Contacts (Customers & vendors), enabled by both business recipes |
| Legacy | BOOK-07 Customers, BOOK-14 Vendors, BOOK-15 Vendor Categories |
Features and dependencies
CrestApps.Almohaseb.Contacts depends on:
CrestApps.Almohaseb(the foundation) andCrestApps.Almohaseb.Ledger(Accounting), for the vendor's default account and the protected tax ID;OrchardCore.Contents;CrestApps.OrchardCore.ContentFields(PhoneField; it brings in CrestApps Resources, Phone Numbers,OrchardCore.ContentFieldsandOrchardCore.ContentTypes);CrestApps.OrchardCore.ContentFields.Address(AddressField; it brings inCrestApps.OrchardCore.Addresses).
The web host references the CrestApps.OrchardCore.ContentFields, CrestApps.OrchardCore.Addresses and CrestApps.OrchardCore.PhoneNumbers packages.
It is a managed feature, not dependency only, because a business keeps customers and vendors before any sales or purchases screen uses them; the Sales and Purchases features depend on it.
Content types
ContactsMigrations.CreateAsync (version 1) defines three types. All are creatable, listable and securable, and neither draftable nor versionable: a contact has one version.
| Type | Parts | Fields (on the type's own part) |
|---|---|---|
AlmohasebCustomer | AlmohasebCustomerPart, AlmohasebCustomer | Address (AddressField, no name or company line, default country US), Phone and Mobile (PhoneField) |
AlmohasebVendor | AlmohasebVendorPart, AlmohasebVendor | the same three fields |
AlmohasebVendorCategory | AlmohasebVendorCategoryPart |
The display text of each item is set by its part driver: the company or the first and last name for a customer (ContactRules.GetCustomerName), the name for a vendor or a category.
CustomerPart
FirstName, LastName, CompanyName, Email, PaymentTermsDays (int?, 0 to 365, null = due on receipt), Notes and IsActive.
VendorPart
Name, CategoryId (the AlmohasebVendorCategory content item id; required, which fixes the legacy crash on a vendor without a category), Email, AccountNumber (50), PaymentTermsDays, DefaultExpenseAccountId (a ledger account of type cost of goods sold, expense, other expense, or a non-system asset), Is1099, TaxIdKind (Ein or Ssn), ProtectedTaxId, TaxIdLastFour and IsActive.
The tax ID is protected with ISensitiveDataProtector under the purpose CrestApps.Almohaseb.Contacts.VendorTaxId (ContactsConstants.TaxIdProtectionPurpose); only the last four digits are stored in clear text, for the masked display. The editor never shows the number: an empty box keeps the saved one, and Remove the saved tax ID clears it. A 1099 vendor needs a tax ID.
VendorCategoryPart
Name, Usage (VendorCategoryUsage flags: Purchases = 1, OperatingExpenses = 2, OtherExpenses = 4, Assets = 8; the legacy "Is In ..." booleans) and IsActive.
Indexes
ContactIndexProvider maps the latest version of each item (ContentItem.Latest) in the default collection:
| Index | Columns | Database indexes |
|---|---|---|
CustomerPartIndex | ContentItemId, Name (display text, 100), Email (255), IsActive | Name, IsActive; ContentItemId |
VendorPartIndex | ContentItemId, Name, CategoryId, Is1099, IsActive | Name, IsActive; CategoryId, IsActive; ContentItemId |
VendorCategoryPartIndex | ContentItemId, Name, Usage, IsActive | Name; ContentItemId |
The table definitions are the public static method ContactsMigrations.CreateIndexTablesAsync.
Rules
ContactRules validates the parts without a database (ContactValidationCode):
| Code | Rule |
|---|---|
NameRequired | A customer has a company, or a first and a last name; a vendor and a category have a name. |
NameTooLong | Names have at most 100 characters. |
DuplicateName | Checked by the drivers against the index: no two customers, vendors or categories share a name. |
InvalidEmail | One bare address with a dotted host (System.Net.Mail.MailAddress). |
PaymentTermsOutOfRange | 0 to 365 days. |
CategoryRequired | A vendor has a category. |
AccountNumberTooLong | At most 50 characters. |
InvalidTaxId | TaxIdRules.TryParse refused the number. |
TaxIdRequiredFor1099 | A 1099 vendor has a tax ID. |
TaxIdRules.TryParse(kind, value, out digits) accepts nine digits with or without dashes and spaces. An EIN goes through EmployerIdentificationNumber.TryParse (no 00 prefix). An SSN refuses the areas 000, 666 and 9xx (except ITIN middle digits 50–65, 70–88, 90–92 and 94–99), the group 00 and the serial 0000. Format writes 12-3456789 or 123-45-6789; Mask writes **-***6789 or ***-**-6789.
Services
| Service | Lifetime | What it does |
|---|---|---|
IContactDirectory / ContactDirectory | Scoped | ListCustomersAsync() (active customers by name) and ListVendorsAsync(usage) (active vendors of the active categories whose Usage has the flag, by name). Entry screens of other modules use it for their pickers. |
Admin
The module adds a Contacts menu group (id almohasebContacts) with Customers, Vendors and Vendor categories (ids almohasebCustomers, almohasebVendors, almohasebVendorCategories). Each item is the Orchard Core content list of its type (/Admin/Contents/ContentItems/{type}) and is shown with that type's ListContent_{type} permission. The part drivers add a ContactSummary shape to the SummaryAdmin display (e-mail, category, 1099 and inactive badges).
Permissions
The module declares no permission of its own. The three types are securable, so the role editor lists the Orchard Core content permissions of each type (List Customer content items, Create Customer, Edit Customer for others, Delete Customer for others and so on). The Administrator role has them all.
Recipes and deployment
Both business recipes enable CrestApps.Almohaseb.Contacts. Customers, vendors and categories are content items, so the Content recipe step and the content deployment steps import and export them; the content definitions come from the migration.
Extension points
- Pickers on entry screens: use
IContactDirectorywith theVendorCategoryUsageof the screen. - Editor cards: the vendor editor is Vendor, Address, Phone numbers and 1099 (the tax ID and Gets a 1099, shape
AlmohasebVendorPart_Tax_Edit, with the Purchases 1099 box atParts:4%1099;3); the customer editor is Customer, Address and Phone numbers. The module'splacement.jsonplaces the address and phone fields and the part wrappers. - More data on a contact: attach your own part or fields to the
AlmohasebCustomerorAlmohasebVendortype in a migration.