def add_permit_lines(self):
        from regional.restrictions import GetMatchingPRsByZip

        if not self.agreement.system_address.zip:
            return

        property_type = 'commercial' if self.agreement.floorplan == 'Business' else 'residential'

        prs = GetMatchingPRsByZip(self.agreement.system_address.zip, property_type, asof=datetime.now())
        print "PRs found: %r" % prs
        permits = [pr for pr in prs if pr.permit_fee or pr.addendum_fee]

        # These are the lines we need permits for.  We're going to cheat
        # our faces off and use the note column for this.

        for pr in permits:
            # reclaim or create a permit line.
            pnote = ';'.join([pr.override_type or pr.region_type, ', '.join(pr.override_name or pr.region_name)])
            pline = self.reclaim_line(code='PERMIT', line_type='PERMIT', note=pnote)
            if not pline:
                pline = InvoiceLine(agreement=self.agreement, line_type='PERMIT')

            pline.update_permit(pr, permit_product=self.products['PERMIT'])
            pline.save()

            # Put the permit line onto the final part.
            self.final_lines.append(pline)
    def sync_all_children(self):
        # First, unclaim any child lines we've claimed in a previous call to this function.  They'll get reclaimed in this function if necessary.
        self.unclaimed_lines = list(set(self.unclaimed_lines + [line for line in self.final_lines if not line.traded and line.parent]))

        # This is a copy of self.final_lines, filtered down to not include child lines (except trades)
        # It's used to detect differences at the end from self.final_lines, and will get assigned there at the end.
        final_lines = [line for line in self.final_lines if line.traded or not line.parent]

        # This function can be called more than once in a row, which is necessary if more lines get added as a result
        # of child lines being added.  (You add a smoke package, it has a smoke detector, which requires the smoke service,
        # hypothetically has a smoke permit kit or something.)

        # A queue of lines that need their children synced.  Starts with final_lines which is the top and traded lines.
        lines_to_sync = list(final_lines)


        pos = 0
        while pos < len(lines_to_sync):
            # walk through each line and sync its children.  As children get added, they'll be queued onto
            # the end of this loop, so they can get their nested children.
            line = lines_to_sync[pos]
            pos += 1

            prod = self.products.get(line.code)
            if not prod:
                self.errors.append("Could not find product %r to sync child lines on line %r" % (line.code, line.pk))
                continue
            # Index the contents of this line's product.
            contents = self.by_code(self.product_contents.get(prod.code, []))

            # for every product in that product:
            for code, pc in contents.iteritems():
                child = self.reclaim_line(parent_id=line.pk, code=code, line_type='CHILD')
                if not child:
                    # If I wasn't able to reclaim an existing child, we need to make a new one for this agreement/line:
                    child = InvoiceLine(agreement=self.agreement, parent=line)

                # sync the child line with the product (gets updated quantity, product type, category, etc.)
                child.update_child(product=self.products[code], pc=pc, parent_line=line)

                # Save this child. It's either been updated or is new.
                child.save()

                # Queue up this line to be synced for ITS children
                lines_to_sync.append(child)
                # and add it to final_lines
                final_lines.append(child)

        # Did the final set of lines change from what we had before?
        changed = set(final_lines) ^ set(self.final_lines)

        # And then, assign the final set of children.
        self.final_lines = final_lines

        return bool(changed)
    def add_mandatory_product(self, code, quantity):
        # The function needs to check to see if it is already satisfied before
        # calling this. This function will always reclaim or create a new line
        # with the specified quantity. this is because add_mandatory_items
        # gets called multiple times, but does NOT unclaim everything like
        # sync_all_children does, because it may be that the mandatory items
        # themselves require more mandatory items. (Ex: for some reason,
        # businesses in california MUST have a smoke detector.)


        mp = self.reclaim_line(code=code, line_type='MANDATORY')
        if not mp:
            mp = InvoiceLine(agreement=self.agreement)
            product = self.products.get(code)
            if not product:
                self.errors.append('Could not add mandatory product %r' % code)
                return
            price = self.prices.get(code)
            if not price:
                self.errors.append('Mandatory product %r has no price.  Campaign=%r' % (code, self.agreement.campaign_id))

            mp.update_mandatory(quantity=quantity, product=product, price=price, pricedate=self.agreement.pricedate)

        mp.quantity = quantity
        mp.save()
        self.final_lines.append(mp)
Example #4
0
def Warehouse():
    china_cur = ChinaCursor()
    china_cur.SetCrossServerFlags()
    sql = '''
        SELECT cd.agreement_id, blob, date_created, date_modified as date_modified
        FROM contract_details cd
        LEFT JOIN contracts c on c.agreement_id = cd.agreement_id
    '''
    china_cur.execute(sql)
    campaigns = {c.pk: c for c in Campaign.objects.all()}
    existing = list(Agreement.objects.all().values_list('id', flat=True))

    while True:
        merchandise = china_cur.fetch_many()

        for m in merchandise:
            if m['agreement_id'] in existing:
                continue
            blob = loads(m['blob'])
            blob['date_created'] = m['date_created']
            blob['date_modified'] = m['date_modified']

            agreement = Agreement()

            agreement.id = m['agreement_id']

            blob_campaign = blob['campaign_id'].upper()
            campaign = campaigns.get(blob_campaign)

            campaign_id = None
            if not campaign:
                cur = GladosCursor()
                sql = '''
                    SELECT campaign_id, name
                    FROM campaigns
                    WHERE campaign_id = ?
                '''
                cur.execute(sql, [blob_campaign])
                prev_campaign = cur.fetchone()

                if not prev_campaign:
                    new_campaign = Campaign()
                    new_campaign.campaign_id = blob_campaign
                    new_campaign.name = blob_campaign
                    new_campaign.save()
                    campaign_id = new_campaign.pk
                else:
                    new_campaign = Campaign()
                    new_campaign.campaign_id = blob_campaign
                    new_campaign.name = prev_campaign.name
                    new_campaign.save()
                    campaign_id = new_campaign.pk
            else:
                campaign_id = campaign.campaign_id
            agreement.campaign_id = campaign_id

            applicant_id = None
            if 'applicant' in blob.keys():
                if not blob['applicant']:
                    first_name = ''
                    last_name = ''
                    initial = ''
                    phone = ''
                    applicant_id = Customer(first_name, last_name, initial, phone)
                else:
                    first_name = blob['applicant']['first_name']
                    last_name = blob['applicant']['last_name']
                    initial = blob['applicant']['middle_initial']
                    phone = None
                    if not blob['phone1']:
                        phone = ''
                    else:
                        phone = blob['phone1']
                    applicant_id = Customer(first_name, last_name, initial, phone)
            else:
                first_name = ''
                last_name = ''
                initial = ''
                phone = ''
                applicant_id = Customer(first_name, last_name, initial, phone)
            agreement.applicant_id = applicant_id

            agreement.coapplicant = None
            if 'coapplicant' in blob.keys():
                if not blob['coapplicant']:
                    agreement.coapplicant_id = None
                else:
                    first_name = blob['coapplicant']['first_name']
                    last_name = blob['coapplicant']['last_name']
                    initial = blob['coapplicant']['middle_initial']
                    phone = blob['phone1']
                    create_coapplicant = Customer(first_name, last_name, initial, phone)
                    agreement.coapplicant_id = create_coapplicant

            billing_address_id = None
            if 'address' in blob.keys():
                if not blob['address']:
                    address = ''
                    city = ''
                    state = ''
                    zipcode = ''
                    country = ''
                    billing_address_id = Location(address, city, state, zipcode, country)
                else:
                    address = blob['address']['address1']
                    city = blob['address']['city']
                    state = blob['address']['state']
                    zipcode = blob['address']['zipcode']
                    country = 'US'
                    billing_address_id = Location(address, city, state, zipcode, country)
            else:
                address = ''
                city = ''
                state = ''
                zipcode = ''
                country = ''
                billing_address_id = Location(address, city, state, zipcode, country)
            agreement.billing_address_id = billing_address_id
            agreement.system_address_id = billing_address_id

            # going to use this date again, so just going to create it first before assignment
            pricetable_date = blob['date_created']
            agreement.pricetable_date = pricetable_date or datetime(1900, 1, 1, 0, 0)

            agreement.email = blob['email']

            approved = None
            if blob['credit_status'] == 'APPROVED DCS':
                approved = 'DCS'
            else:
                approved = blob['credit_status']
            agreement.approved = approved

            agreement.package_id = None
            if 'package' in blob.keys():
                if not blob['package']:
                    agreement.package_id = ''
                else:
                    selected_package = blob['package']['code'].lower()
                    package = Package.objects.get(code=selected_package)
                    agreement.package_id = package.pk

            agreement.shipping = None
            if 'shipping' in blob.keys():
                if not blob['shipping']:
                    agreement.shipping = ''
                else:
                    agreement.shipping = blob['shipping']['code']
            else:
                agreement.shipping = ''

            agreement.monitoring = None
            if 'monitoring' in blob.keys():
                if not blob['monitoring']:
                    agreement.monitoring = ''
                else:
                    agreement.monitoring = blob['monitoring']['code']
            else:
                agreement.monitoring = ''

            agreement.floorplan = blob['floorplan']
            agreement.promo_code = ''

            # since these are existing records, we will assume that these things have been done
            agreement.done_premium = '1'
            agreement.done_combo = '1'
            agreement.done_alacarte = '1'
            agreement.done_closing = '1'
            agreement.done_package = '1'
            agreement.done_promos = '1'

            agreement.save()

            agreement_object = Agreement.objects.get(id=m['agreement_id'])

            if 'package' in blob.keys():
                package = blob['package']
                if package:
                    invoice = InvoiceLine()
                    invoice.agreement = agreement_object
                    invoice.note = ''
                    invoice.product = package['code']
                    invoice.pricetable = blob['pricetable']
                    invoice.quantity = '1'
                    invoice.upfront_each = package['upfront_price']
                    invoice.upfront_total = package['upfront_price']
                    invoice.upfront_strike = package['retail_price']
                    invoice.monthly_each = package['monthly_price']
                    invoice.monthly_total = package['monthly_price']
                    invoice.save()

            if 'monitoring' in blob.keys():
                monitoring = blob['monitoring']
                if monitoring:
                    invoice = InvoiceLine()
                    invoice.agreement = agreement_object
                    invoice.note = ''
                    invoice.product = monitoring['code']
                    invoice.pricetable = blob['pricetable']
                    invoice.quantity = '1'
                    invoice.pricedate = pricetable_date
                    invoice.upfront_each = monitoring['upfront_price']
                    invoice.upfront_total = monitoring['upfront_price']
                    invoice.upfront_strike = monitoring['retail_price']
                    invoice.monthly_each = monitoring['monthly_price']
                    invoice.monthly_total = monitoring['monthly_price']
                    invoice.save()

            equipment = blob['equipment']
            if equipment:
                for e in equipment:
                    invoice = InvoiceLine()
                    invoice.agreement = agreement_object
                    # there is a reason in the blob, perhaps note needs to be changed to reason?
                    invoice.note = e['reason']
                    invoice.product = e['part']
                    invoice.pricetable = blob['pricetable']
                    invoice.quantity = e['quantity']
                    invoice.pricedate = pricetable_date
                    invoice.upfront_each = None
                    if e['upfront_price'] == 0:
                        invoice.upfront_each = e['upfront_price']
                    else:
                        invoice.upfront_each = e['upfront_price']
                    invoice.upfront_total = float(invoice.upfront_each) * invoice.quantity
                    invoice.monthly_each = None
                    if e['monthly_price'] == 0:
                        invoice.monthly_each = e['monthly_price']
                    else:
                        invoice.monthly_each = e['monthly_price']
                    invoice.monthly_total = float(invoice.monthly_each) * invoice.quantity
                    invoice.save()

            if 'shipping' in blob.keys():
                shipping = blob['shipping']
                if shipping:
                    invoice = InvoiceLine()
                    invoice.agreement = agreement_object
                    invoice.note = ''
                    invoice.product = shipping['code']
                    invoice.pricetable = blob['pricetable']
                    invoice.quantity = '1'
                    invoice.pricedate = pricetable_date
                    invoice.upfront_each = shipping['upfront_price']
                    invoice.upfront_total = shipping['upfront_price']
                    invoice.save()

            services = blob['services']
            if services:
                for s in services:
                    invoice = InvoiceLine()
                    invoice.agreement = agreement_object
                    invoice.note = ''
                    invoice.product = s['service']
                    invoice.pricetable = blob['pricetable']
                    invoice.quantity = '1'
                    invoice.pricedate = pricetable_date
                    invoice.upfront_price = s['upfront_price']
                    invoice.upfront_total = s['upfront_price']
                    invoice.upfront_strike = s['retail_price']
                    invoice.monthly_price = s['monthly_price']
                    invoice.monthly_total = s['monthly_price']
                    invoice.save()

    return
    def update_invoice_lines(self):

        # The incoming invoice lines should look like:
        '''
        [{
            'code': 'COPPER',
            'quantity': 1
            'traded': true // or not present.
        }, ...]
        '''

        # coerce the incoming invoice lines:
        incoming_lines = [IL(line, updater=self) for line in self.blob['invoice_lines']]
        # If the IL constructor put any errors in, stop now.
        if self.errors:
            return

        # Next get every existing invoice line.
        self.existing_lines = list(self.agreement.invoice_lines.all())
        self.unclaimed_lines = list(self.existing_lines)  # Unclaim all existing lines.  We may reclaim them soon.

        # this is the list of lines that will be on the agreement at the end:
        self.final_lines = []

        for il in list(incoming_lines):
            if not il.price:
                incoming_lines.remove(il)
                self.messages.append('%s removed from the agreement because it is not available.' % il.code)
                continue
            available = getattr(il.price, 'available_mask', None)
            if available is None:
                available = il.price.available
            if not available:
                incoming_lines.remove(il)
                self.messages.append('%s removed from the agreement because it is no longer available.' % il.code)
                continue



        # First, do every line that came in from the system NOT traded.
        # Invoice Lines for these should all be TOP.
        # (This includes package, monitoring, alacarte, but not children, mandatory services...)
        for il in incoming_lines:
            if not il.line_type == 'TOP':
                continue
            # il is a fakey line.
            line = self.reclaim_line(code=il.code, line_type='TOP')
            if not line:
                line = InvoiceLine(agreement=self.agreement)
            line.update_top(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate)

            self.final_lines.append(line)

        # Now do it again for trade lines.
        for il in incoming_lines:
            if not il.line_type == 'TRADE':
                continue

            line = self.reclaim_line(code=il.code, line_type='TRADE')
            if not line:
                line = InvoiceLine(agreement=self.agreement)

            line.update_trade(product=il.product, quantity=il.quantity, price=il.price, pricedate=self.agreement.pricedate)

            self.final_lines.append(line)

        # Save any lines in final_lines because they'll need pks for their children.
        for line in self.final_lines:
            line.save()

        print "Final lines BEFORE CHILD SYNC:"
        for line in self.final_lines:
            print "{}, {}, {}".format(line.code, line.quantity, line.traded)


        # loop through, adding mandatory items and syncing children until no changes are made.
        loops = 0
        self.sync_all_children()
        while True:
            # Next, we need to process mandatory items.
            changed = self.add_mandatory_items()

            # Then, sync children again.
            changed = self.sync_all_children() or changed

            if not changed:
                break

            loops += 1
            if loops >= 10:
                self.errors.append("Probably an infinite loop in mandatories/children.  Needs fixin.")
                break

        # Next reclaim/create a permit line if needed.
        self.add_permit_lines()

        self.sanity_check()

        print "Final lines:"
        for line in self.final_lines:
            print "{}, {}, {}".format(line.code, line.quantity, line.traded)

        # Finally, any lines that are in existing_lines but not in final_lines should be deleted.
        for orphan in self.existing_lines:
            if orphan in self.final_lines:
                continue
            orphan.delete()