--[[ @Title: Record Death Data (UK) @Type: Source-driven data entry @Subtype: "Civil Registration Certificate" @Author: Calico Pie @Version: 1.3 @GH #10 #14 #15 #23 #54 #76 #112 #119 @Keywords: @LastUpdated: November 2021 @Description: Based on the format of the England and Wales Death Certificate since 1837, this plugin allows entry of all details including informant, residences, etc. ]] fhInitialise(7) fh = require 'fhUtils' fh.setIupDefaults() -- Local Globals local form, templateName, templateDefault local iForm = 1 local sPluginName = fhGetContextInfo 'CI_PLUGIN_NAME' local s = {} -- Autofill table local pCite -- Citation Object local tUpdatedFields = {} -- Added and updated fields local cells = {} -- Main Dialog sections s['PLAC'] = fh.createPlaceList() s['BIRTPLAC'] = s['PLAC'] --- Builds dialog and drives process. function main() -- ------------------------------------------------------------Load citation and associated fields pCite = fh.loadPreparedCitation() if not pCite.result then fh.getParam(sPluginName, pCite.err) return end -- Ensure all needed fields have been completed if not ( pCite:checkRequired('EN-TYPE', 'NM-PRINCIPAL', 'DT-DATE', 'PL-LOCATION') ) then fh.getParam( sPluginName, 'Not all required fields are set,\nplease ensure you have entered type, date, location and principal. ' ) return end if pCite:getValue 'EN-TYPE' ~= 'Death' then fh.getParam(sPluginName, 'Only Death is supported by this plugin. ') return end -- Get form and load values from Citation local masterForms = loadMasterForms() form = tablex.deepcopy(masterForms[iForm]['sections']) templateName = masterForms[iForm]['templateName'] templateDefault = masterForms[iForm]['templateDefault'] form.principal.fields[1].value = pCite:getValue 'NM-PRINCIPAL' dtEventDateString = pCite:getDisplayValue 'DT-DATE' dtEventDate = pCite:getValue 'DT-DATE' -- ------------------------------------------------------------ Get currently selected person local ptrPrincipal = fh.getCurrentIndividual() if ptrPrincipal:IsNotNull() then form.principal.fields[field(form.principal.fields, 'RECORD')].value = ptrPrincipal:Clone() form.principal.fields[field(form.principal.fields, 'ACTION')].value = 'select' form.principal.fields[field(form.principal.fields, 'RECORD')].protect = false form.principal.fields[field(form.principal.fields, 'SEX')].value = fhGetItemText( ptrPrincipal, '~.SEX' ) end -- ------------------------------------------------------------ Create Dialog for k, v in pairs(form) do grid = iup.gridbox { numdiv = 2, cgaplin = '1', cgapcol = '1', margin = '4x4', expand = 'YES', } for l, f in ipairs(v.fields) do if f.label then local label = ' ' local value = ' ' if f.gridDisplay or v.gridDisplay then label = f.label .. ':' value = fh.getParamValueForDisplay(f, true) end f.gridLabel = iup.label { title = label, size = '80', expand = 'NO' } iup.Append(grid, f.gridLabel) f.iupgrid = iup.label { title = value, expand = 'YES' } iup.Append(grid, f.iupgrid) end end v.button = iup.button { title = 'Edit', active = 'NO' } if v.active then v.button.active = 'YES' end v.button.action = function() doEdit(k, v.title, v.seq) end cells[v.seq] = iup.vbox { EXPANDCHILDREN = 'YES', EXPAND = 'YES', iup.frame { title = v.title, EXPANDCHILDREN = 'YES', EXPAND = 'YES', iup.vbox { EXPANDCHILDREN = 'YES', EXPAND = 'YES', v.button, grid, }, }, } end local placeList = fh.createPlaceList() s['PLAC'] = placeList s['OCCU'] = fhGetDataList 'OCCUPATIONS' local addressList = {} txtMessage = iup.label { title = ' Hint: please edit the Principal section to enable the other sections', } btnOk = iup.button { title = 'OK', padding = '20x4', expand = 'HORIZONTAL' } function btnOk.action() local sType = 'principal' local fields = form[sType]['fields'] if form[sType]['fields'][field(fields, 'AGE')].value == '' and form[sType]['fields'][field(fields, 'DATE')].value:IsNull() then fhMessageBox 'Age and Date of Birth can not both be blank' return end if form.principal.valid then local sVenue = pCite:getValue 'TX-CHURCH' if not sVenue then sVenue = pCite:getValue 'AD-ADDRESS' end processDeath(pCite:getValue 'PL-LOCATION', sVenue) return iup.CLOSE else fhMessageBox 'Information has not been entered on both Principal' end end btnCancel = iup.button { title = 'Cancel', padding = '4x4', expand = 'HORIZONTAL' } function btnCancel.action() return iup.CLOSE end local sTitle = 'Death Entry: ' .. fhGetDisplayText(pCite.source) dlg = iup.dialog { title = sTitle, minsize = '1000', iup.vbox { EXPANDCHILDREN = 'YES', EXPAND = 'YES', iup.gridbox { numdiv = 2, cgaplin = '1', cgapcol = '1', margin = '4x4', expand = 'YES', EXPANDCHILDREN = 'YES', table.unpack(cells), }, iup.hbox { margin = '4x4', expand = 'NO', btnOk, btnCancel, fh.helpButton 'record-Death-data-uk', txtMessage, }, }, } iup.SetAttribute(dlg, 'NATIVEPARENT', fhGetContextInfo 'CI_PARENT_HWND') -- Set the parent window handle iup.SetHandle("main", dlg) iup.SetGlobal('PARENTDIALOG', 'main') iup.Popup(dlg) iup.Destroy(dlg) end -- --------------------------------------------------------------- doEdit --- Called from the Edit buttons to update the sections -- @param sType string, section name from form table -- @param sTitle string Name of dialog -- @param seq number, sequence number of section function doEdit(sType, sTitle, seq) local fields = form[sType].fields if sType == 'principal' then local oldRecord = form[sType]['fields'][field(fields, 'RECORD')].value:Clone() local r = fh.getParam( 'Enter ' .. sTitle, nil, fields, { 'OK', 'Cancel' }, s ) if r.ok then form[sType].valid = true -- enable all Edit buttons for k, v in pairs(form) do v.button.active = 'YES' end end else local r = fh.getParam( 'Enter ' .. sTitle, nil, fields, { 'OK', 'Cancel' }, s ) if r.ok then form[sType].valid = true form[sType].gridDisplay = true end end updateGrid() end -- --------------------------------------------------------------- updateGrid --- Update All Grid Fields from table function updateGrid() for sType, sSection in pairs(form) do for l, f in ipairs(sSection.fields) do local label = ' ' local value = ' ' if f.gridDisplay or form[sType].gridDisplay then label = f.label value = fh.getParamValueForDisplay(f, true) end if f.gridLabel then f.gridLabel.title = label end if f.iupgrid then f.iupgrid.title = value end end end end function processDeath(sPlace, sAddress, sCelebrant) local fields = {} local data = {} for k, s in pairs(form) do data[k] = {} for i, f in ipairs(s.fields) do data[k][f.tag] = { value = f.value, type = f.type, dr = f.df } end end -- Create needed Individual Records for _, f in pairs(data) do if f.ACTION and f.ACTION.value == 'create' then local sex if f.SEX and f.SEX.value then sex = f.SEX.value end local ptr = fh.createIndi(f.NAME.value, sex) local ptrName = fhGetItemPtr(ptr, '~.NAME') addCitation(ptr, 'Created') addCitation(ptrName, 'Cited') f.RECORD.value:MoveTo(ptr) end end local eventDate = pCite:getValue 'DT-DATE' local sPlace = pCite:getValue 'PL-LOCATION' local sAddress = pCite:getValue 'AD-ADDRESS' -- Create / Update Death Event local ptrDeath = fhGetItemPtr(data.principal.RECORD.value, '~.DEAT') local sAction = 'Added' if ptrDeath:IsNotNull() then ptrDeath, sAction = fh.createUpdateFact( data.principal.RECORD.value, 'DEAT', 'Death', sPlace, eventDate, sAddress ) else ptrDeath = fh.createFact( data.principal.RECORD.value, 'DEAT', sPlace, eventDate, sAddress ) end if ptrDeath then addCitation(ptrDeath, sAction) -- Add Age local ptrAge = fhCreateItem('AGE', ptrDeath, true) if ptrAge and fh.isSet(data.principal.AGE.value) then fhSetValueAsText(ptrAge, data.principal.AGE.value) end -- Add Cause local ptrCause = fhCreateItem('CAUS', ptrDeath, true) if ptrCause and fh.isSet(data.principal.CAUSE.value) then fhSetValueAsText(ptrCause, data.principal.CAUSE.value) end end -- Create Update Birth Event local dtBirth = data.principal.DATE.value if dtBirth:IsNull() and fh.isSet(data.principal.AGE.value) then dtBirth = fh.calcBirth(eventDate, data.principal.AGE.value) end if not (dtBirth:IsNull()) then local ptrBirth = fhGetItemPtr(data.principal.RECORD.value, '~.BIRT') local sPlace = '' if data.principal.BIRTPLAC.value ~= 'N/A' then sPlace = data.principal.BIRTPLAC.value end if ptrBirth:IsNotNull() then ptrBirth, sAction = fh.createUpdateFact( data.principal.RECORD.value, 'BIRT', 'Birth', sPlace, dtBirth ) else sAction = 'Added' ptrBirth = fh.createFact( data.principal.RECORD.value, 'BIRT', sPlace, dtBirth ) end if ptrBirth then addCitation(ptrBirth, sAction) end end for k, f in pairs(data) do if f.RECORD and fh.isSet(f.RECORD.value) then if f.OCCU and f.OCCU.value:len() > 0 then local ptrFact ptrFact, sAction = fh.createFact( f.RECORD.value, 'OCCU', nil, eventDate, nil, f.OCCU.value ) if ptrFact then addCitation(ptrFact, 'Added') end end if f.PLAC and f.PLAC.value:len() > 0 then local ptrFact, sAction = fh.createFact( f.RECORD.value, 'RESI', f.PLAC.value, eventDate, f.ADDR.value ) if ptrFact then addCitation(ptrFact, 'Added') end end end if ptrDeath and k == 'informant' then if f.ACTION.value == 'name' then if fh.isSet(f.NAME.value) then fh.addWitness(ptrDeath, f.NAME.value, 'Informant') end elseif fh.isSet(f.RECORD.value) then fh.addWitness(ptrDeath, f.RECORD.value, 'Informant') end end end local fields = {} for k, s in pairs(form) do for i, f in ipairs(s.fields) do local inx = string.upper(k .. '.' .. tostring(f.tag)) fields[inx] = fh.getParamValueForDisplay(f) if f.tag == 'NAME' and data[k].RECORD then local ptr = data[k].RECORD.value if ptr:IsNotNull() then -- Add record link fields[inx] = fh.richTextRecordLink(ptr, fields[inx]) end end end end if not (pCite:checkRequired 'AD-ADDRESS') then fields['AD-ADDRESS'] = '' end sText = fh.formatTextFromSource(templateName, templateDefault, pCite, fields) fh.createTextFromSource(pCite, sText, 'source') fh.outputUpdatedFields(tUpdatedFields, pCite) end function addCitation(ptr, action) local action = action or '' table.insert(tUpdatedFields, { ptr:Clone(), action }) pCite:appendCitation(ptr) end function selectOrCreate(value) if value == 'select' then return false, 1 else return true, 0 end end function updateSex(ptr) if ptr:IsNull() then return { 'Male', 'Female', 'Unknown' } else return fhGetItemText(ptr, '~.SEX') end end function address(place) local addr = fh.createAddressList(place) return addr end function field(fields, tag) local i for i, v in ipairs(fields) do if tag == v.tag then return i end end end function loadMasterForms() ptrFamily = fhNewItemPtr() masterForms = {} masterForms[1] = { templateName = 'Death Certificate (UK).ftf', templateDefault = [[Death certificate {NM-PRINCIPAL} {DT-DATE} Certified Copy of an entry of Death given at {REG.LOCATION} Registration District {REG.DISTRICT} in sub-district of {REG.SUB} in the county of {REG.PLAC} When and Where died | Name and Surname | Sex | Age / Birth Date | Occupation | Cause of Death | Signature, description and residence of informant | When Registered | Signature of Registrar {DT-DATE} {AD-ADDRESS} {PL-LOCATION} | {PRINCIPAL.NAME} {PRINCIPAL.ADDR} {PRINCIPAL.PLAC} | {PRINCIPAL.SEX} | {PRINCIPAL.AGE} {PRINCIPAL.DATE} |{PRINCIPAL.OCCU} |{PRINCIPAL.CAUSE} Certified by {PRINCIPAL.CERTIFED_BY} | {INFORMANT.NAME} {INFORMANT.DESCRIPTION} {INFORMANT.ADDR} {INFORMANT.PLAC} | {REG.DATE} | {REG.NAME} Maiden Name: {PRINCIPAL.MAIDEN} Birth Place: {PRINCIPAL.BIRTPLAC} ]], sections = { reg = { fields = { { tag = 'LOCATION', type = 'STRING', label = 'Location', value = 'General Register Office', }, { tag = 'DISTRICT', type = 'STRING', label = 'District', value = '' }, { tag = 'SUB', type = 'STRING', label = 'Sub-District', value = '' }, { tag = 'PLAC', type = 'STRING', label = 'County of', value = '' }, { tag = 'NAME', type = 'STRING', label = 'Registrars Name', value = '' }, { tag = 'DATE', type = 'DATE', label = 'Registration Date', value = fhNewDate(), }, }, title = 'Registration Information', label = 'principal', seq = 1, active = true, }, principal = { fields = { { tag = 'NAME', label = 'Name', type = 'STRING', dr = 'NAME', value = pCite:getValue 'NM-PRINCIPAL', minlength = 1, protect = true, }, { tag = 'ACTION', label = 'Add principal as', type = 'LIST', value = 'create', values = { 'create', 'select' }, prompts = { 'Create New Record', 'Use Existing Record' }, child = 'RECORD', childUpdate = function(...) return selectOrCreate(...) end, }, { tag = 'RECORD', label = 'Record', type = 'RECORD', dr = 'PTR', value = fhNewItemPtr(), protect = true, child = 'SEX', childUpdate = updateSex, }, { tag = 'SEX', type = 'LIST', label = 'Sex', dr = 'SEX', value = 'Male', values = { 'Male', 'Female', 'Unknown' }, }, { tag = 'CAUSE', dr = 'OCCU', type = 'STRING', label = 'Cause of Death', value = '', }, { tag = 'CERTIFED_BY', dr = 'OCCU', type = 'STRING', label = 'Certified By', value = '', }, { tag = 'OCCU', dr = 'OCCU', type = 'STRING', label = 'Occupation', value = '' }, { tag = 'AGE', type = 'STRING', label = 'Age', value = '', mask = '(/d+[dwmy])', minlength = 0, }, { tag = 'DATE', type = 'DATE', label = 'Date of Birth', value = fhNewDate() }, { tag = 'PLAC', type = 'STRING', label = 'Place of Residence', value = '', child = 'ADDR', childUpdate = address, }, { tag = 'ADDR', type = 'STRING', label = 'Address of Residence', value = '' }, { tag = 'BIRTPLAC', type = 'STRING', label = 'Birth Place', value = 'N/A' }, { tag = 'MAIDEN', type = 'STRING', label = 'Maiden Name', value = 'N/A' }, }, title = 'Principal', label = 'principal', seq = 2, active = true, gridDisplay = true, }, informant = { fields = { { tag = 'NAME', label = 'Name', type = 'STRING', dr = 'NAME', value = '', minlength = 1, }, { tag = 'DESCRIPTION', label = 'Description', type = 'STRING', value = '', minlength = 1, }, { tag = 'ACTION', label = 'Add informant as', type = 'LIST', value = 'name', values = { 'name', 'create', 'select' }, prompts = { 'Name Only', 'Create New Record', 'Use Existing Record' }, child = 'RECORD', childUpdate = selectOrCreate, }, { tag = 'RECORD', label = 'Record', type = 'RECORD', recordtype = 'INDI', value = fhNewItemPtr(), protect = true, }, { tag = 'PLAC', type = 'STRING', label = 'Residence Place', dr = 'RESI.PLAC', value = '', }, { tag = 'ADDR', type = 'STRING', label = 'Residence Address', dr = 'RESI.ADDR', value = '', }, }, title = 'Informant', seq = 3, active = true, }, }, } return masterForms end -------------------------------------------------------------------------------------------------------- Start Plugin main()