Skip to content

Commit

Permalink
18495 - Add Memorandum Update to COOP Correction - Update Filer, Lega…
Browse files Browse the repository at this point in the history
…l-API, Emailer (#2353)
  • Loading branch information
Jxio authored Dec 12, 2023
1 parent bb0d802 commit e050a0f
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
<div class="separator mt-4"></div>
{% endif %}

{% if memorandumInResolution %}
{% if memorandumInResolution or uploadNewMemorandum %}
<div class="no-page-break">
<div class="section-title mt-4">Memorandum <span class="correction-label">CORRECTED</span></div>
</div>
{% if uploadNewMemorandum %}
<div class="section-data mt-4">A certified copy of the uploaded memorandum is attached with this filing.</div>
{% else %}
<div class="section-data mt-4">Changes will be described in the special resolution text.</div>
{% endif %}
<div class="separator mt-4"></div>
{% endif %}
5 changes: 3 additions & 2 deletions legal-api/src/legal_api/core/filing_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ def is_special_resolution_correction_by_meta_data(filing):
if filing.meta_data and (correction_meta_data := filing.meta_data.get('correction')):
# Note these come from the corrections filer.
sr_correction_meta_data_keys = ['hasResolution', 'memorandumInResolution', 'rulesInResolution',
'uploadNewRules', 'toCooperativeAssociationType', 'toLegalName']
'uploadNewRules', 'uploadNewMemorandum',
'toCooperativeAssociationType', 'toLegalName']
for key in sr_correction_meta_data_keys:
if key in correction_meta_data:
return True
Expand All @@ -23,7 +24,7 @@ def is_special_resolution_correction_by_filing_json(filing: Dict):
# Note this relies on the filing data once. This is acceptable inside of the filer (which runs once)
# and emailer (runs on PAID which is before the filer and runs on COMPLETED).
# For filing data that persists in the database, attempt to use the meta_data instead.
sr_correction_keys = ['rulesInResolution', 'resolution', 'rulesFileKey',
sr_correction_keys = ['rulesInResolution', 'resolution', 'rulesFileKey', 'rulesMemorandumKey',
'memorandumInResolution', 'cooperativeAssociationType']
for key in sr_correction_keys:
if key in filing.get('correction'):
Expand Down
2 changes: 2 additions & 0 deletions legal-api/src/legal_api/core/meta/filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ def alter_outputs_correction(filing, business, outputs):
outputs.add('certificateOfNameChange')
if filing.meta_data.get('correction', {}).get('uploadNewRules'):
outputs.add('certifiedRules')
if filing.meta_data.get('correction', {}).get('uploadNewMemorandum'):
outputs.add('certifiedMemorandum')
if filing.meta_data.get('correction', {}).get('hasResolution'):
outputs.add('specialResolution')
return outputs
Expand Down
1 change: 1 addition & 0 deletions legal-api/src/legal_api/reports/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,7 @@ def _format_resolution_data(self, filing: Filing):
filing['newCoopAssociationType'] = ASSOCIATION_TYPE_DESC.get(to_association_type, '')
filing['rulesInResolution'] = filing.get(filing_source, {}).get('rulesInResolution')
filing['uploadNewRules'] = meta_data.get(filing_source, {}).get('uploadNewRules')
filing['uploadNewMemorandum'] = meta_data.get(filing_source, {}).get('uploadNewMemorandum')
filing['memorandumInResolution'] = filing.get(filing_source, {}).get('memorandumInResolution')
if (resolution_date_str := filing.get(filing_source, {}).get('resolutionDate', None)):
resolution_date = LegislationDatetime.as_legislation_timezone_from_date_str(resolution_date_str)
Expand Down
50 changes: 35 additions & 15 deletions legal-api/src/legal_api/services/filings/validations/correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,22 +132,28 @@ def _validate_special_resolution_correction(filing_dict, legal_type, msg):
msg.extend(court_order_validation(filing_dict))
if filing_dict.get('filing', {}).get(filing_type, {}).get('correction', {}).get('rulesFileKey', None):
msg.extend(rules_change_validation(filing_dict))
if filing_dict.get('filing', {}).get(filing_type, {}).get('correction', {}).get('memorandumFileKey', None):
msg.extend(memorandum_change_validation(filing_dict))
if is_special_resolution_correction_by_filing_json(filing_dict.get('filing', {})):
if filing_dict.get('filing', {}).get('correction', {}).get('parties', None):
err = validate_roles(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)
# FUTURE: this should be removed when COLIN sync back is no longer required.
err = validate_parties_names(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)

err = validate_parties_mailing_address(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)
else:
err_path = f'/filing/{filing_type}/parties/roles'
msg.append({'error': 'Parties list cannot be empty or null', 'path': err_path})
_validate_roles_parties_correction(filing_dict, legal_type, filing_type, msg)


def _validate_roles_parties_correction(filing_dict, legal_type, filing_type, msg):
if filing_dict.get('filing', {}).get('correction', {}).get('parties', None):
err = validate_roles(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)
# FUTURE: this should be removed when COLIN sync back is no longer required.
err = validate_parties_names(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)

err = validate_parties_mailing_address(filing_dict, legal_type, filing_type)
if err:
msg.extend(err)
else:
err_path = f'/filing/{filing_type}/parties/roles'
msg.append({'error': 'Parties list cannot be empty or null', 'path': err_path})


def validate_party(filing: Dict, legal_type: str) -> list:
Expand Down Expand Up @@ -243,3 +249,17 @@ def rules_change_validation(filing):
msg.extend(rules_err)
return msg
return []


def memorandum_change_validation(filing):
"""Validate memorandum change."""
msg = []
memorandum_file_key_path: Final = '/filing/correction/memorandumFileKey'
memorandum_file_key: Final = get_str(filing, memorandum_file_key_path)

if memorandum_file_key:
rules_err = validate_pdf(memorandum_file_key, memorandum_file_key_path)
if rules_err:
msg.extend(rules_err)
return msg
return []
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,9 @@ def filer_action(filing_name, filing_json, meta_data, business):

if filing_json['filing']['correction'].get('rulesFileKey'):
meta_data['correction']['uploadNewRules'] = True

if filing_json['filing']['correction'].get('memorandumFileKey'):
meta_data['correction']['uploadNewMemorandum'] = True

if filing_json['filing']['correction'].get('resolution'):
meta_data['correction']['hasResolution'] = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ def _get_pdfs(
attach_order += 1
elif is_cp_special_resolution:
rules_changed = bool(filing.filing_json['filing']['correction'].get('rulesFileKey'))
pdfs = get_completed_pdfs(token, business, filing, name_changed, rules_changed)
memorandum_changed = bool(filing.filing_json['filing']['correction'].get('rulesMemorandumKey'))
pdfs = get_completed_pdfs(token, business, filing, name_changed,
rules_changed=rules_changed, memorandum_changed=memorandum_changed)
return pdfs


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def get_completed_pdfs(
business: dict,
filing: Filing,
name_changed: bool,
rules_changed=False) -> list:
rules_changed=False,
memorandum_changed=False) -> list:
# pylint: disable=too-many-locals, too-many-branches, too-many-statements, too-many-arguments
"""Get the completed pdfs for the special resolution output."""
pdfs = []
Expand Down Expand Up @@ -101,6 +102,25 @@ def get_completed_pdfs(
)
attach_order += 1

# Certified Memorandum
if memorandum_changed:
memorandum = requests.get(
f'{current_app.config.get("LEGAL_API_URL")}/businesses/{business["identifier"]}/filings/{filing.id}'
'?type=certifiedMemorandum',
headers=headers
)
if memorandum.status_code == HTTPStatus.OK:
certified_memorandum_encoded = base64.b64encode(memorandum.content)
pdfs.append(
{
'fileName': 'Certified Memorandum.pdf',
'fileBytes': certified_memorandum_encoded.decode('utf-8'),
'fileUrl': '',
'attachOrder': attach_order
}
)
attach_order += 1

return pdfs


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
{% if filing['rulesFileKey'] %}
<li>Certified Rules</li>
{% endif %}
{% if filing['rulesMemorandumKey'] %}
<li>Certified Memorandum</li>
{% endif %}
</ul>

[[business-dashboard-link.html]]
Expand Down
28 changes: 28 additions & 0 deletions queue_services/entity-emailer/tests/unit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,34 @@ def prep_cp_special_resolution_correction_filing(session, business, original_fil
return filing


def prep_cp_special_resolution_correction_upload_memorandum_filing(session, business,
original_filing_id,
payment_id, option,
corrected_filing_type):
"""Return a cp special resolution correction filing prepped for email notification."""
filing_template = copy.deepcopy(FILING_HEADER)
filing_template['filing']['header']['name'] = 'correction'
filing_template['filing']['correction'] = copy.deepcopy(CORRECTION_CP_SPECIAL_RESOLUTION)
filing_template['filing']['business'] = {'identifier': business.identifier}
filing_template['filing']['correction']['contactPoint']['email'] = 'cp_sr@test.com'
filing_template['filing']['correction']['correctedFilingId'] = original_filing_id
filing_template['filing']['correction']['correctedFilingType'] = corrected_filing_type
del filing_template['filing']['correction']['resolution']
filing_template['filing']['correction']['memorandumFileKey'] = '28f73dc4-8e7c-4c89-bef6-a81dff909ca6.pdf'
filing_template['filing']['correction']['memorandumFileName'] = 'test.pdf'
filing = create_filing(token=payment_id, filing_json=filing_template, business_id=business.id)
filing.payment_completion_date = filing.filing_date
# Triggered from the filer.
filing._meta_data = {'correction': {'uploadNewMemorandum': True}}
filing.save()
if option in ['COMPLETED']:
uow = versioning_manager.unit_of_work(session)
transaction = uow.create_transaction(session)
filing.transaction_id = transaction.id
filing.save()
return filing


class Obj:
"""Make a custom object hook used by dict_to_obj."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ def correct_business_data(business: Business, # pylint: disable=too-many-locals
filing_meta.correction = {**filing_meta.correction,
**{'uploadNewRules': True}}

# update memorandum, if any
with suppress(IndexError, KeyError, TypeError):
memorandum_file_key = dpath.util.get(correction_filing, '/correction/memorandumFileKey')
memorandum_file_name = dpath.util.get(correction_filing, '/correction/memorandumFileName')
if memorandum_file_key:
rules_and_memorandum.update_memorandum(business, correction_filing_rec,
memorandum_file_key, memorandum_file_name)
filing_meta.correction = {**filing_meta.correction,
**{'uploadNewMemorandum': True}}

with suppress(IndexError, KeyError, TypeError):
if dpath.util.get(correction_filing, '/correction/memorandumInResolution'):
filing_meta.correction = {**filing_meta.correction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def update_rules(
def update_memorandum(
business: Business,
filing: Filing,
memorandum_file_key: String
memorandum_file_key: String,
file_name: String = None
) -> Optional[List]:
"""Updtes memorandum if any.
Expand All @@ -67,9 +68,10 @@ def update_memorandum(
# if nothing is passed in, we don't care and it's not an error
return None

is_correction = filing.filing_type == 'correction'
# create certified copy for memorandum document
memorandum_file = MinioService.get_file(memorandum_file_key)
registrar_stamp_data = RegistrarStampData(filing.effective_date, business.identifier)
registrar_stamp_data = RegistrarStampData(filing.effective_date, business.identifier, file_name, is_correction)
replace_file_with_certified_copy(memorandum_file.data, memorandum_file_key, registrar_stamp_data)

document = Document()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def __init__(self, file_content):


def test_correction_coop_rules(app, session, minio_server):
"""Assert that the coop rules is altered."""
"""Assert that the coop rules and memorandum is altered."""
# Create business
identifier = 'CP1234567'
business = create_entity(identifier, 'CP', 'COOP INC.')
Expand All @@ -197,6 +197,9 @@ def test_correction_coop_rules(app, session, minio_server):
rules_file_key_uploaded_by_user = upload_file('rules.pdf')
correction_filing['filing']['correction']['rulesFileKey'] = rules_file_key_uploaded_by_user
correction_filing['filing']['correction']['rulesFileName'] = 'rules.pdf'
memorandum_file_key_uploaded_by_user = upload_file('memorandum.pdf')
correction_filing['filing']['correction']['memorandumFileKey'] = memorandum_file_key_uploaded_by_user
correction_filing['filing']['correction']['memorandumFileName'] = 'memorandum.pdf'

payment_id = str(random.SystemRandom().getrandbits(0x58))

Expand Down Expand Up @@ -224,3 +227,14 @@ def test_correction_coop_rules(app, session, minio_server):
rules_files_obj = MinioService.get_file(rules_file_key_uploaded_by_user)
assert rules_files_obj
assert_pdf_contains_text('Filed on ', rules_files_obj.read())

memorandum_document = session.query(Document). \
filter(Document.filing_id == filing_submission.id). \
filter(Document.type == DocumentType.COOP_MEMORANDUM.value). \
one_or_none()

assert memorandum_document.file_key == correction_filing['filing']['correction']['memorandumFileKey']
assert MinioService.get_file(memorandum_document.file_key)
memorandum_files_obj = MinioService.get_file(memorandum_file_key_uploaded_by_user)
assert memorandum_files_obj
assert_pdf_contains_text('Filed on ', memorandum_files_obj.read())

0 comments on commit e050a0f

Please sign in to comment.