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
Esempio n. 3
0
    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
Esempio n. 4
0
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()
Esempio n. 6
0
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)
Esempio n. 15
0
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
Esempio n. 17
0
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)
Esempio n. 19
0
def create_domain(domain):
    print 'Creating domain {}'.format(domain)
    get_or_create(db.session, model=AcceptedEmailDomains, domain=domain)
    db.session.commit()
    print 'Done'
    return