def schedule_job(self): '''Schedule a job. If the time_override param is set to True, it will override the timing. This allows us to always run jobs from the tests or manually force a job to be scheduled if necessary. In order to schedule a job, one of the following conditions must be met: 1. ``start_time`` is none 2. The current time is after the ``start_time`` 3. The ``time_override`` attribute is set to True Returns: If all the conditions for scheduling a job are true, a new :py:class:`~purchasing.jobs.job_base.JobStatus` model will be created or selected and returned. ''' start_time = self.start_time if isinstance(self.start_time, datetime.time): start_time = self.build_datetime_object(self.start_time) if start_time is None or \ UTC.localize(datetime.datetime.utcnow()) > start_time.astimezone(UTC) or \ self.time_override is True: model, exists = get_or_create( db.session, self.job_status_model, name=self.name, date=datetime.date.today() ) if not exists: model.update(status='new') return model, exists
def schedule_job(self): '''Schedule a job. If the time_override param is set to True, it will override the timing. This allows us to always run jobs from the tests or manually force a job to be scheduled if necessary. ''' start_time = self.start_time if isinstance(self.start_time, datetime.time): start_time = self.build_datetime_object(self.start_time) if start_time is None or \ UTC.localize(datetime.datetime.utcnow()) > start_time.astimezone(UTC) or \ self.time_override is True: model, exists = get_or_create( db.session, self.job_status_model, name=self.name, date=datetime.date.today() ) if not exists: model.update(status='new') return model, exists
def schedule_job(self): '''Schedule a job. If the time_override param is set to True, it will override the timing. This allows us to always run jobs from the tests or manually force a job to be scheduled if necessary. In order to schedule a job, one of the following conditions must be met: 1. ``start_time`` is none 2. The current time is after the ``start_time`` 3. The ``time_override`` attribute is set to True Returns: If all the conditions for scheduling a job are true, a new :py:class:`~purchasing.jobs.job_base.JobStatus` model will be created or selected and returned. ''' start_time = self.start_time if isinstance(self.start_time, datetime.time): start_time = self.build_datetime_object(self.start_time) if start_time is None or \ UTC.localize(datetime.datetime.utcnow()) > start_time.astimezone(UTC) or \ self.time_override is True: model, exists = get_or_create(db.session, self.job_status_model, name=self.name, date=datetime.date.today()) if not exists: model.update(status='new') return model, exists
def start_work(contract_id=-1): contract = ContractBase.query.get(contract_id) contract = contract if contract else ContractBase() form = NewContractForm(obj=contract) if form.validate_on_submit(): if contract_id == -1: contract, _ = get_or_create( db.session, ContractBase, description=form.data.get('description'), department=form.data.get('department'), is_visible=False ) else: contract = ContractBase.clone(contract) contract.description = form.data.get('description') contract.department = form.data.get('department') db.session.add(contract) db.session.commit() assigned = assign_a_contract(contract, form.data.get('flow'), form.data.get('assigned').id, clone=False) db.session.commit() if assigned: flash('Successfully assigned {} to {}!'.format(assigned.description, assigned.assigned.email), 'alert-success') return redirect(url_for('conductor.detail', contract_id=assigned.id)) else: flash("That flow doesn't exist!", 'alert-danger') return render_template('conductor/new.html', form=form, contract_id=contract_id)
def main(file_target='./files/2015-05-27-nigp-cleaned.csv'): data = extract(file_target) for row in data: subcat, new_subcat = get_or_create( db.session, Category, nigp_codes=parse_codes(convert_empty_to_none(row.get('code'))), category=convert_empty_to_none(row.get('parent_category')), subcategory=convert_empty_to_none(row.get('category')), category_friendly_name=convert_empty_to_none(row.get('category_friendly_name')), examples=convert_empty_to_none(row.get('examples')), examples_tsv=parse_examples_tsv(convert_empty_to_none(row.get('examples'))) ) if new_subcat: db.session.add(subcat) db.session.commit()
def save_line_item(_line_items, contract): ''' Saves the line items to the db ''' for item in _line_items: unit_cost, percentage = parse_currency(item.get('description'), item.get('unit_cost')) total_cost, _ = parse_currency(item.get('description'), item.get('total_cost')) linked_company = db.session.execute( ''' SELECT id, company_name FROM company WHERE company_name ilike '%' || :name || '%' OR (select count(*) from ( select regexp_matches(lower(company_name), lower(:name)) ) x ) > 0 ''', { 'name': item.get('company') }).fetchone() company_id = linked_company[0] if linked_company else None line_item, new_line_item = get_or_create( db.session, LineItem, contract_id=contract.id, description=item.get('description'), manufacturer=item.get('manufacturer'), model_number=item.get('model_number'), quantity=item.get('quantity'), unit_of_measure=item.get('unit_of_measure'), unit_cost=unit_cost, total_cost=total_cost, percentage=percentage, company_name=item.get('company'), company_id=company_id) if new_line_item: db.session.add(line_item) db.session.commit() return
def save_line_item(_line_items, contract): ''' Saves the line items to the db ''' for item in _line_items: unit_cost, percentage = parse_currency(item.get('description'), item.get('unit_cost')) total_cost, _ = parse_currency(item.get('description'), item.get('total_cost')) linked_company = db.session.execute(''' SELECT id, company_name FROM company WHERE company_name ilike '%' || :name || '%' OR (select count(*) from ( select regexp_matches(lower(company_name), lower(:name)) ) x ) > 0 ''', { 'name': item.get('company') } ).fetchone() company_id = linked_company[0] if linked_company else None line_item, new_line_item = get_or_create( db.session, LineItem, contract_id=contract.id, description=item.get('description'), manufacturer=item.get('manufacturer'), model_number=item.get('model_number'), quantity=item.get('quantity'), unit_of_measure=item.get('unit_of_measure'), unit_cost=unit_cost, total_cost=total_cost, percentage=percentage, company_name=item.get('company'), company_id=company_id ) if new_line_item: db.session.add(line_item) db.session.commit() return
def main(file_target='./files/2015-05-27-nigp-cleaned.csv'): data = extract(file_target) for row in data: subcat, new_subcat = get_or_create( db.session, Category, nigp_codes=parse_codes(convert_empty_to_none(row.get('code'))), category=convert_empty_to_none(row.get('parent_category')), subcategory=convert_empty_to_none(row.get('category')), category_friendly_name=convert_empty_to_none( row.get('category_friendly_name')), examples=convert_empty_to_none(row.get('examples')), examples_tsv=parse_examples_tsv( convert_empty_to_none(row.get('examples')))) if new_subcat: db.session.add(subcat) db.session.commit()
def main(filetarget, filename, access_key, access_secret, bucket): if not re.match(VALID_FILENAMES, filename): raise IOError('Not a valid filename. Filenames must have COSTARS with number separated by a dash (Ex. "COSTARS-3.csv").') data = extract(filetarget) s3_files = None # connect to s3 and get contents of bucket bucket = connect_to_s3_bucket(access_key, access_secret, bucket) if bucket: s3_files = bucket.list() try: for row in data: try: turn_off_sqlalchemy_events() except InvalidRequestError: pass company, new_company = get_or_create( db.session, Company, company_name=convert_empty_to_none(row.get('Company')) ) company_contact = determine_company_contact(row) if company_contact: # create the new company contact company_contact, new_contact = get_or_create( db.session, CompanyContact, company_id=company.id, **company_contact ) if new_contact: db.session.add(company_contact) db.session.commit() costars_awardee = convert_empty_to_none(row.get('Company')) try: expiration = datetime.datetime.strptime(row.get('Expiration'), '%m/%d/%y') except ValueError: expiration = None costars_type, _ = get_or_create( db.session, ContractType, name='COSTARS' ) # create or select the contract object contract, new_contract = get_or_create( db.session, ContractBase, contract_type=costars_type, expiration_date=expiration, financial_id=convert_empty_to_none(row.get('CONTROLLER')), description='{costars} - {company}'.format( costars=filename.replace('-', ' ').rstrip('.csv').upper(), company=costars_awardee ) ) # connect to s3 if s3_files: # all files start with 'costars-{number}-', which we should be # able to get from our filename max_ratio = (None, 0) startswith = filename.strip('.csv').lower() for _file in s3_files: _filename = _file.name.encode('utf-8').strip('.pdf').rstrip('.') costars_awardee = costars_awardee.rstrip('.') # because the file start patterns are consistent, strip # out the costars-{number}- _file_awardee = _filename.split('-')[2] # check for absolute matches match_ratio = SM(lambda x: bool(re.match(JUNK_STRING, x)), costars_awardee, _file_awardee).ratio() if match_ratio == 1: # this is an absolute match, insert it into the db and break max_ratio = (_file.generate_url(expires_in=0, query_auth=False), match_ratio) if _filename.startswith(startswith): break else: continue elif match_ratio > max_ratio[1]: # this is the best match we have so far max_ratio = (_file.generate_url(expires_in=0, query_auth=False), match_ratio) continue # use the best match that we have print contract.description, max_ratio if max_ratio[1] > 0.7: contract.contract_href = max_ratio[0] for k, v in row.iteritems(): if k in CONSTANT_FIELDS: continue # insert a new contract property with where the company is located elif k == 'County Located': if row.get('County Located') != '': county_located, new_county_located = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='Located in', value=convert_empty_to_none( '{county} County'.format(county=row.get('County Located')) ) ) else: continue if new_county_located: db.session.add(county_located) # insert a new property with the listed manufacturers elif k == 'Manufacturers': if convert_empty_to_none(row.get('Manufacturers')): manufacturer, new_manufacturer = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='List of manufacturers', value=convert_empty_to_none(row.get('Manufacturers')) ) if new_manufacturer: db.session.add(manufacturer) # we are treating everything else like a line item, # so upload all of those pieces else: if convert_to_bool(convert_empty_to_none(v)): line_item, new_line_item = get_or_create( db.session, LineItem, contract_id=contract.id, description=convert_empty_to_none(k) ) else: continue if new_line_item: db.session.add(line_item) contract.companies.append(company) db.session.commit() except Exception: db.session.rollback() raise finally: turn_on_sqlalchemy_events()
def edit_company_contacts(contract_id): '''Update information about company contacts, and save all information New :py:class:`~purchasing.data.contracts.ContractBase` objects are created for each unique controller number. Notifications are also sent to all of the original contract's followers to say that the contract information has been replaced/updated with new info. :param contract_id: Primary key ID for a :py:class:`~purchasing.data.contracts.ContractBase` .. seealso:: * :py:class:`~purchasing.conductor.forms.CompanyContactListForm` * :py:meth:`~purchasing.data.contracts.ContractBase.create` * :py:meth:`~purchasing.data.contracts.ContractBase.complete` * :py:class:`~purchasing.notifications.Notification` :status 200: Render the CompanyContactListForm form :status 302: Post the data and redirect back to the success view, or redirect back to contract or company views if those haven't been completed yet. :status 404: Contract not found ''' contract = ContractBase.query.get(contract_id) if contract and session.get( 'contract-{}'.format(contract_id)) is not None and session.get( 'companies-{}'.format(contract_id)) is not None: form = CompanyContactListForm() # pull out companies from session, order them by financial id # so that they can be grouped appropriately companies = sorted(json.loads( session['companies-{}'.format(contract_id)]), key=lambda x: x.get('financial_id')) if form.validate_on_submit(): main_contract = contract for ix, _company in enumerate(companies): contract_data = json.loads( session['contract-{}'.format(contract_id)]) # because multiple companies can have the same name, don't use # get_or_create because it can create multiples if _company.get('company_id') > 0: company = Company.query.get(_company.get('company_id')) else: company = Company.create( company_name=_company.get('company_name')) # contacts should be unique to companies, though try: for _contact in form.data.get('companies')[ix].get( 'contacts'): _contact['company_id'] = company.id contact, _ = get_or_create(db.session, CompanyContact, **_contact) # if there are no contacts, an index error will be thrown for this company # so we catch it and just pass except IndexError: pass contract_data['financial_id'] = _company['financial_id'] if contract.financial_id is None or contract.financial_id == _company[ 'financial_id']: contract.update_with_spec_number(contract_data, company=company) else: contract = ContractBase.clone(contract, parent_id=contract.parent_id, strip=False) contract.update_with_spec_number(contract_data, company=company) contract.is_visible = True db.session.commit() Notification(to_email=[i.email for i in contract.followers], from_email=current_app.config['CONDUCTOR_SENDER'], reply_to=current_user.email, subject='A contract you follow has been updated!', html_template='conductor/emails/new_contract.html', contract=main_contract).send(multi=True) session.pop('contract-{}'.format(contract_id)) session.pop('companies-{}'.format(contract_id)) session['success-{}'.format(contract_id)] = True current_app.logger.info(''' CONDUCTOR CONTRACT COMPLETE - company contacts for contract "{}" assigned. |New contract(s) successfully created''' .format(contract.description)) if contract.parent: contract.parent.complete() return redirect( url_for('conductor.success', contract_id=main_contract.id)) if len(form.companies.entries) == 0: for company in companies: form.companies.append_entry() return render_template('conductor/edit/edit_company_contacts.html', form=form, contract=contract, companies=companies) elif session.get('contract-{}'.format(contract_id)) is None: return redirect(url_for('conductor.edit', contract_id=contract_id)) elif session.get('companies-{}'.format(contract_id)) is None: return redirect( url_for('conductor.edit_company', contract_id=contract_id)) abort(404)
def main(filetarget, filename, access_key, access_secret, bucket): if not re.match(VALID_FILENAMES, filename): raise IOError( 'Not a valid filename. Filenames must have COSTARS with number separated by a dash (Ex. "COSTARS-3.csv").' ) data = extract(filetarget) s3_files = None # connect to s3 and get contents of bucket bucket = connect_to_s3_bucket(access_key, access_secret, bucket) if bucket: s3_files = bucket.list() try: for row in data: try: turn_off_sqlalchemy_events() except InvalidRequestError: pass company, new_company = get_or_create( db.session, Company, company_name=convert_empty_to_none(row.get('Company'))) company_contact = determine_company_contact(row) if company_contact: # create the new company contact company_contact, new_contact = get_or_create( db.session, CompanyContact, company_id=company.id, **company_contact) if new_contact: db.session.add(company_contact) db.session.commit() costars_awardee = convert_empty_to_none(row.get('Company')) try: expiration = datetime.datetime.strptime( row.get('Expiration'), '%m/%d/%y') except ValueError: expiration = None costars_type, _ = get_or_create(db.session, ContractType, name='COSTARS') # create or select the contract object contract, new_contract = get_or_create( db.session, ContractBase, contract_type=costars_type, expiration_date=expiration, financial_id=convert_empty_to_none(row.get('CONTROLLER')), description='{costars} - {company}'.format( costars=filename.replace('-', ' ').rstrip('.csv').upper(), company=costars_awardee)) # connect to s3 if s3_files: # all files start with 'costars-{number}-', which we should be # able to get from our filename max_ratio = (None, 0) startswith = filename.strip('.csv').lower() for _file in s3_files: _filename = _file.name.encode('utf-8').strip( '.pdf').rstrip('.') costars_awardee = costars_awardee.rstrip('.') # because the file start patterns are consistent, strip # out the costars-{number}- _file_awardee = _filename.split('-')[2] # check for absolute matches match_ratio = SM(lambda x: bool(re.match(JUNK_STRING, x)), costars_awardee, _file_awardee).ratio() if match_ratio == 1: # this is an absolute match, insert it into the db and break max_ratio = (_file.generate_url(expires_in=0, query_auth=False), match_ratio) if _filename.startswith(startswith): break else: continue elif match_ratio > max_ratio[1]: # this is the best match we have so far max_ratio = (_file.generate_url(expires_in=0, query_auth=False), match_ratio) continue # use the best match that we have print contract.description, max_ratio if max_ratio[1] > 0.7: contract.contract_href = max_ratio[0] for k, v in row.iteritems(): if k in CONSTANT_FIELDS: continue # insert a new contract property with where the company is located elif k == 'County Located': if row.get('County Located') != '': county_located, new_county_located = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='Located in', value=convert_empty_to_none( '{county} County'.format( county=row.get('County Located')))) else: continue if new_county_located: db.session.add(county_located) # insert a new property with the listed manufacturers elif k == 'Manufacturers': if convert_empty_to_none(row.get('Manufacturers')): manufacturer, new_manufacturer = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='List of manufacturers', value=convert_empty_to_none( row.get('Manufacturers'))) if new_manufacturer: db.session.add(manufacturer) # we are treating everything else like a line item, # so upload all of those pieces else: if convert_to_bool(convert_empty_to_none(v)): line_item, new_line_item = get_or_create( db.session, LineItem, contract_id=contract.id, description=convert_empty_to_none(k)) else: continue if new_line_item: db.session.add(line_item) contract.companies.append(company) db.session.commit() except Exception: db.session.rollback() raise finally: turn_on_sqlalchemy_events()
def main(file_target='./files/2015-05-05-contractlist.csv'): data = extract(file_target) try: for row in data: # create or select the company try: turn_off_sqlalchemy_events() except InvalidRequestError: pass try: company, new_company = get_or_create( db.session, Company, company_name=convert_empty_to_none(row.get('COMPANY')) ) except IntegrityError: db.session.rollback() company = None company_contact = determine_company_contact(row) if company_contact and company: # create the new company contact company_contact, new_contact = get_or_create( db.session, CompanyContact, company_id=company.id, **company_contact ) if new_contact: db.session.add(company_contact) db.session.commit() try: expiration = datetime.datetime.strptime(row.get('EXPIRATION'), '%m/%d/%y') except ValueError: expiration = None try: _financial_id = convert_empty_to_none(row.get('CONTROLLER')) except ValueError: _financial_id = None contract_type, _ = get_or_create( db.session, ContractType, name=convert_empty_to_none(row.get('TYPE OF CONTRACT')) ) # create or select the contract object contract, new_contract = get_or_create( db.session, ContractBase, contract_type=contract_type, expiration_date=expiration, financial_id=_financial_id, description=convert_empty_to_none(row.get('SERVICE')) ) if contract.contract_type == 'County': contract.contract_href = BASE_CONTRACT_URL.format( number=convert_contract_number(convert_empty_to_none(row.get('CONTRACT'))) ) contract_number, new_contract_number = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='Spec Number', value=convert_empty_to_none(row.get('CONTRACT')) ) if new_contract_number: db.session.add(contract_number) if company: contract.companies.append(company) db.session.commit() except Exception: db.session.rollback() raise finally: turn_on_sqlalchemy_events()
def main(file_target='./files/2015-10-27-state-contracts.csv'): data = extract(file_target) try: for row in data: try: turn_off_sqlalchemy_events() except InvalidRequestError: pass # create or select the company try: company, new_company = get_or_create( db.session, Company, company_name=convert_empty_to_none(row.get('COMPANY'))) except IntegrityError: db.session.rollback() company = None company_contact = determine_company_contact(row) if company_contact and company: # create the new company contact company_contact, new_contact = get_or_create( db.session, CompanyContact, company_id=company.id, **company_contact) if new_contact: db.session.add(company_contact) db.session.commit() try: expiration = datetime.datetime.strptime( row.get('EXPIRATION'), '%m/%d/%Y') except ValueError: expiration = None try: _financial_id = convert_empty_to_none(row.get('CONTROLLER')) except ValueError: _financial_id = None contract_type, _ = get_or_create(db.session, ContractType, name=convert_empty_to_none( row.get('TYPE OF CONTRACT'))) # create or select the contract object contract, new_contract = get_or_create( db.session, ContractBase, contract_type=contract_type, expiration_date=expiration, financial_id=_financial_id, description=convert_empty_to_none(row.get('SERVICE')), contract_href=BASE_CONTRACT_URL.format( number=convert_empty_to_none(row.get('CONTRACT')), type='Overview' if 'IT SERVICES ITQ' in convert_empty_to_none( row.get('SERVICE')).upper() else 'ContractFile')) parent_number, new_parent_number = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='Parent Number', value=convert_empty_to_none(row.get('PARENT'))) if new_parent_number: db.session.add(parent_number) contract_number, new_contract_number = get_or_create( db.session, ContractProperty, contract_id=contract.id, key='Contract Number', value=convert_empty_to_none(row.get('CONTRACT'))) if new_contract_number: db.session.add(contract_number) if company: contract.companies.append(company) db.session.commit() except Exception: db.session.rollback() raise finally: turn_on_sqlalchemy_events()
def start_work(contract_id=-1): '''Start work on a contract When new work is started on a contract, a new contract is created (either as a clone of an existing contract, or as brand new work), assigned to the :py:class:`~purchasing.data.flows.Flow` and :py:class:`~purchasing.users.models.User` indicated in the :py:class:`~purchasing.conductor.forms.NewContractForm` :param contract_id: Primary key ID for a :py:class:`~purchasing.data.contracts.ContractBase` .. seealso:: :py:meth:`~purchasing.data.contracts.ContractBase.clone` for more information on how new contracts get started, and :py:class:`~purchasing.conductor.forms.NewContractForm` for more on the form to start new work. :status 200: Render the new contract view :status 302: Create or start new work on a cloned contract ''' contract = ContractBase.query.get(contract_id) if contract: first_stage = contract.get_first_stage() if first_stage and contract.completed_last_stage(): pass elif first_stage and first_stage.stage_id != contract.current_stage_id: return redirect(url_for('conductor.detail', contract_id=contract.id)) elif first_stage: contract.start = localize_datetime(contract.get_first_stage().entered) else: contract = ContractBase() form = NewContractForm(obj=contract) if form.validate_on_submit(): if contract_id == -1: contract, _ = get_or_create( db.session, ContractBase, description=form.data.get('description'), department=form.data.get('department'), is_visible=False ) elif not first_stage or contract.completed_last_stage(): contract = ContractBase.clone(contract) contract.description = form.data.get('description') contract.department = form.data.get('department') db.session.add(contract) db.session.commit() assigned = assign_a_contract( contract, form.data.get('flow'), form.data.get('assigned'), start_time=form.data.get('start').astimezone(pytz.UTC).replace(tzinfo=None), clone=False ) db.session.commit() if assigned: flash('Successfully assigned {} to {}!'.format(assigned.description, assigned.assigned.email), 'alert-success') return redirect(url_for('conductor.detail', contract_id=assigned.id)) else: flash("That flow doesn't exist!", 'alert-danger') return render_template('conductor/new.html', form=form, contract_id=contract_id, contract=contract)
def start_work(contract_id=-1): '''Start work on a contract When new work is started on a contract, a new contract is created (either as a clone of an existing contract, or as brand new work), assigned to the :py:class:`~purchasing.data.flows.Flow` and :py:class:`~purchasing.users.models.User` indicated in the :py:class:`~purchasing.conductor.forms.NewContractForm` :param contract_id: Primary key ID for a :py:class:`~purchasing.data.contracts.ContractBase` .. seealso:: :py:meth:`~purchasing.data.contracts.ContractBase.clone` for more information on how new contracts get started, and :py:class:`~purchasing.conductor.forms.NewContractForm` for more on the form to start new work. :status 200: Render the new contract view :status 302: Create or start new work on a cloned contract ''' contract = ContractBase.query.get(contract_id) if contract: first_stage = contract.get_first_stage() if first_stage and first_stage.stage_id != contract.current_stage_id: return redirect( url_for('conductor.detail', contract_id=contract.id)) elif first_stage: contract.start = localize_datetime( contract.get_first_stage().entered) else: contract = ContractBase() form = NewContractForm(obj=contract) if form.validate_on_submit(): if contract_id == -1: contract, _ = get_or_create( db.session, ContractBase, description=form.data.get('description'), department=form.data.get('department'), is_visible=False) elif not first_stage: contract = ContractBase.clone(contract) contract.description = form.data.get('description') contract.department = form.data.get('department') db.session.add(contract) db.session.commit() assigned = assign_a_contract( contract, form.data.get('flow'), form.data.get('assigned'), start_time=form.data.get('start').astimezone( pytz.UTC).replace(tzinfo=None), clone=False) db.session.commit() if assigned: flash( 'Successfully assigned {} to {}!'.format( assigned.description, assigned.assigned.email), 'alert-success') return redirect( url_for('conductor.detail', contract_id=assigned.id)) else: flash("That flow doesn't exist!", 'alert-danger') return render_template('conductor/new.html', form=form, contract_id=contract_id, contract=contract)
def create_domain(domain): print 'Creating domain {}'.format(domain) get_or_create(db.session, model=AcceptedEmailDomains, domain=domain) db.session.commit() print 'Done' return
def edit_company_contacts(contract_id): contract = ContractBase.query.get(contract_id) if contract and session.get('contract') is not None and session.get('companies') is not None: form = CompanyContactListForm() companies = json.loads(session['companies']) contract_data = json.loads(session['contract']) if form.validate_on_submit(): main_contract = contract for ix, _company in enumerate(companies): # because multiple companies can have the same name, don't use # get_or_create because it can create multiples if _company.get('company_id') > 0: company = Company.query.get(_company.get('company_id')) else: company = Company.create(company_name=_company.get('company_name')) # contacts should be unique to companies, though for _contact in form.data.get('companies')[ix].get('contacts'): _contact['company_id'] = company.id contact, _ = get_or_create(db.session, CompanyContact, **_contact) contract_data['financial_id'] = _company['financial_id'] if ix == 0: contract.update_with_spec_number(contract_data, company=company) else: contract = ContractBase.clone(contract, parent_id=contract.parent_id, strip=False) contract.update_with_spec_number(contract_data, company=company) contract.is_visible = True contract.parent.is_archived = True if not contract.parent.description.endswith('[Archived]'): contract.parent.description += ' [Archived]' db.session.commit() Notification( to_email=[i.email for i in contract.followers], from_email=current_app.config['CONDUCTOR_SENDER'], reply_to=current_user.email, subject='A contract you follow has been updated!', html_template='conductor/emails/new_contract.html', contract=main_contract ).send(multi=True) session.pop('contract') session.pop('companies') session['success'] = True current_app.logger.info(''' CONDUCTOR CONTRACT COMPLETE - company contacts for contract "{}" assigned. New contract(s) successfully created'''.format( contract.description )) return redirect(url_for('conductor.success', contract_id=main_contract.id)) if len(form.companies.entries) == 0: for company in companies: form.companies.append_entry() return render_template( 'conductor/edit/edit_company_contacts.html', form=form, contract=contract, companies=companies ) elif session.get('contract') is None: return redirect(url_for('conductor.edit', contract_id=contract_id)) elif session.get('companies') is None: return redirect(url_for('conductor.edit_company', contract_id=contract_id)) abort(404)
def edit_company_contacts(contract_id): '''Update information about company contacts, and save all information New :py:class:`~purchasing.data.contracts.ContractBase` objects are created for each unique controller number. Notifications are also sent to all of the original contract's followers to say that the contract information has been replaced/updated with new info. :param contract_id: Primary key ID for a :py:class:`~purchasing.data.contracts.ContractBase` .. seealso:: * :py:class:`~purchasing.conductor.forms.CompanyContactListForm` * :py:meth:`~purchasing.data.contracts.ContractBase.create` * :py:meth:`~purchasing.data.contracts.ContractBase.complete` * :py:class:`~purchasing.notifications.Notification` :status 200: Render the CompanyContactListForm form :status 302: Post the data and redirect back to the success view, or redirect back to contract or company views if those haven't been completed yet. :status 404: Contract not found ''' contract = ContractBase.query.get(contract_id) if contract and session.get('contract-{}'.format(contract_id)) is not None and session.get('companies-{}'.format(contract_id)) is not None: form = CompanyContactListForm() # pull out companies from session, order them by financial id # so that they can be grouped appropriately companies = sorted( json.loads(session['companies-{}'.format(contract_id)]), key=lambda x: x.get('financial_id') ) if form.validate_on_submit(): main_contract = contract for ix, _company in enumerate(companies): contract_data = json.loads(session['contract-{}'.format(contract_id)]) # because multiple companies can have the same name, don't use # get_or_create because it can create multiples if _company.get('company_id') > 0: company = Company.query.get(_company.get('company_id')) else: company = Company.create(company_name=_company.get('company_name')) # contacts should be unique to companies, though try: for _contact in form.data.get('companies')[ix].get('contacts'): _contact['company_id'] = company.id contact, _ = get_or_create(db.session, CompanyContact, **_contact) # if there are no contacts, an index error will be thrown for this company # so we catch it and just pass except IndexError: pass contract_data['financial_id'] = _company['financial_id'] if contract.financial_id is None or contract.financial_id == _company['financial_id']: contract.update_with_spec_number(contract_data, company=company) else: contract = ContractBase.clone(contract, parent_id=contract.parent_id, strip=False) contract.update_with_spec_number(contract_data, company=company) contract.is_visible = True db.session.commit() Notification( to_email=[i.email for i in contract.followers], from_email=current_app.config['CONDUCTOR_SENDER'], reply_to=current_user.email, subject='A contract you follow has been updated!', html_template='conductor/emails/new_contract.html', contract=main_contract ).send(multi=True) session.pop('contract-{}'.format(contract_id)) session.pop('companies-{}'.format(contract_id)) session['success-{}'.format(contract_id)] = True current_app.logger.info(''' CONDUCTOR CONTRACT COMPLETE - company contacts for contract "{}" assigned. |New contract(s) successfully created'''.format( contract.description )) if contract.parent: contract.parent.complete() return redirect(url_for('conductor.success', contract_id=main_contract.id)) if len(form.companies.entries) == 0: for company in companies: form.companies.append_entry() return render_template( 'conductor/edit/edit_company_contacts.html', form=form, contract=contract, companies=companies ) elif session.get('contract-{}'.format(contract_id)) is None: return redirect(url_for('conductor.edit', contract_id=contract_id)) elif session.get('companies-{}'.format(contract_id)) is None: return redirect(url_for('conductor.edit_company', contract_id=contract_id)) abort(404)