def calculateQuote(project, misc_modifier, gst_rate): layout_id = project.layout_selected appearance_id = project.appearance_selected layout = dbSession.query(Layout).filter( Layout.layout_id == layout_id).one() appearance = dbSession.query(Appearance).filter( Appearance.appearance_id == appearance_id).one() appearance_value, removal_value, gate_single_value, gate_double_value = Appearances.getAppearanceValues( appearance) # Get layout info and pass to parser parsed = DiagramParser.parse(layout.layout_info) # Pass parsed layout to calculate prices for each object prices = QuoteCalculation.prices(parsed, appearance_value, removal_value, gate_single_value, gate_double_value) # Calculate subtotal, gst, and total subtotal = PriceCalculation.subtotal(prices) if misc_modifier is not None: subtotal += misc_modifier gst = subtotal * gst_rate total = subtotal + gst # PDF Should be generated too return subtotal, gst, total
def getMaterialAmount(layout): """Gets material amounts for calculations""" parsed = DiagramParser.parse(layout.layout_info) num_t_post, num_corner_post, num_line_post, num_end_post, num_gate_posts, num_steel_post = posts( parsed) num_caps = num_steel_post num_collars = num_steel_post * 2 num_small_sections, num_medium_sections, num_big_sections, num_sections = sections( parsed) num_uchannel = num_sections * 2 num_metal_uchannel = num_medium_sections + num_big_sections num_rails = num_sections * 2 num_panels = panels(parsed) num_hinges, num_latches, num_Lsteel = gates(parsed) return { 'metal_post': num_steel_post, 'metal_u_channel': num_metal_uchannel, 'metal_lsteel': num_Lsteel, 'plastic_t_post': num_t_post, 'plastic_corner_post': num_corner_post, 'plastic_line_post': num_line_post, 'plastic_end_post': num_end_post, 'plastic_gate_post': num_gate_posts, 'plastic_rail': num_rails, 'plastic_u_channel': num_uchannel, 'plastic_panel': num_panels, 'plastic_collar': num_collars, 'plastic_cap': num_caps, 'gate_hinge': num_hinges, 'gate_latch': num_latches }
def sendQuote(): """Email a quote to a customer""" proj_id = request.args.get('proj_id') custEmail = request.json['email'] pdf = None if "pdf" in request.json: if request.json["pdf"] != "": pdf = request.json["pdf"] project = dbSession.query(Project).filter( Project.project_id == proj_id).one() customer = dbSession.query(Customer).filter( Customer.customer_id == project.customer_id).one() company = dbSession.query(Company).filter( Company.company_name == project.company_name).one() message = Messages.quoteMessage(customer, company) layout = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one() parsed = DiagramParser.parse(layout.layout_info) if pdf: attachment = pdf else: attachmentString = Messages.quoteAttachment(project, customer, parsed) attachment = Email.makeAttachment(Messages.quotePath, attachmentString) if attachment is not None: Email.send(app, mail, project.company_name, custEmail, "Your quote", message, "Quote", attachment) return "{}"
def projectdetails(project_id): """Retrieve project details""" if request.method == "GET": project = dbSession.query(Project).filter( Project.project_id == project_id).one() selectedLayout = project.layout_selected selectedAppearance = project.appearance_selected layouts = Layouts.getLayouts(project_id) json_layouts = [i.serialize for i in layouts] parsedLayouts = [DiagramParser.parse(i.layout_info) for i in layouts] displayStrings = [] json_appearances = Appearances.getAppearanceList(project_id) customer = dbSession.query(Customer).filter( Customer.customer_id == project.customer_id).one() customerName = customer.first_name customerId = customer.customer_id for layout in parsedLayouts: if layout is None: displayStrings.append([]) else: displayStrings.append(layout.displayStrings()) # Get relative path to project pictures imgPath = repr(os.path.join('..', Pictures.pictureDir, '')) tbnPath = repr(os.path.join('..', Pictures.thumbnailDir, '')) heights = [i.height for i in Estimates.getHeights()] styles = [i.style for i in Estimates.getStyles()] colours = [i.colour for i in Estimates.getColours()] company = dbSession.query(Company).filter( Company.company_name == current_user.company_name).one() companyName = company.company_name supplierEmail = company.supplier_email quote = dbSession.query(Quote).filter( Quote.project_id == project_id).first() if quote is None: quotePdf = "" supplyPdf = "" else: quotePdf = quote.quote_pdf supplyPdf = quote.supply_pdf lst = [ imgPath, tbnPath, json_layouts, json_appearances, companyName, selectedLayout, selectedAppearance, displayStrings, customerName, customerId, heights, styles, colours, supplierEmail, quotePdf, supplyPdf ] return jsonify(lst)
def viewMaterialList(): """Generate and view a material list in a new tab""" proj_id = request.args.get('proj_id') project = dbSession.query(Project).filter( Project.project_id == proj_id).one() layout = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one() parsed = DiagramParser.parse(layout.layout_info) attachmentString = Messages.materialListAttachment(project) attachment = Email.makeAttachment(Messages.materialListPath, attachmentString) if attachment is not None: url = url_for("static", filename=attachment) return jsonify({"url": url}) return jsonify({"reload": 1})
def addLengthLabels(unparsed, parsed): """ Add length labels to a fence diagram and return the result or None if there was a problem """ if (unparsed is None or parsed is None): return None if parsed.empty: return None lowestX = DiagramLabels._getLowestX(parsed) lowestY = DiagramLabels._getLowestY(parsed) svg = DiagramParser.getSVG(unparsed) g = DiagramLabels._getG(svg) if g is None: g = svg for fencingEntity in parsed: # Subtract lowest x and y values to prevent the labels from being # offset by the distance between the origin and the closest shape to # it x = fencingEntity.x - lowestX y = fencingEntity.y - lowestY length = html.escape(fencingEntity.lengthString()) lengthLabel = """<g transform="translate({x},{y})"><foreignObject style="overflow:visible;" pointer-events="all" width="58" height="12"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 60px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;background-color:#ffffff;">{length}</div></div></foreignObject></g>""".format( length=length, x=x, y=y) g.append(ElementTree.fromstring(lengthLabel)) # So labels are not cropped off DiagramLabels._addPadding(svg, 50) ElementTree.register_namespace( "", "http://www.w3.org/2000/svg") xml = ElementTree.tostring(svg, method='xml').decode('utf-8') return DiagramLabels._encode(xml)
def viewQuote(): """Generate and view a quote in a new tab""" proj_id = request.args.get('proj_id') project = dbSession.query(Project).filter( Project.project_id == proj_id).one() customer = dbSession.query(Customer).filter( Customer.customer_id == project.customer_id).one() company = dbSession.query(Company).filter( Company.company_name == project.company_name).one() layout = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one() parsed = DiagramParser.parse(layout.layout_info) attachmentString = Messages.quoteAttachment(project, customer, parsed) attachment = Email.makeAttachment(Messages.quotePath, attachmentString) if attachment is not None: url = url_for("static", filename=attachment) return jsonify({"url": url}) return jsonify({"reload": 1})
def saveDiagram(): """Parse draw io image to get coordinates and measurements""" project_id = request.args.get('proj_id') layout_id = None if 'layoutId' in request.json: layout_id = request.json['layoutId'] layout_name = request.json['name'] image = request.json['image'] parsed = DiagramParser.parse(image) # If the layout already exists and the diagram is empty, do not update it # (tell the client to refresh the page instead to get back the old diagram) if layout_id is not None: if parsed is None: updateLayoutName(layout_id, layout_name) return '{"reload":1}' if parsed.empty: updateLayoutName(layout_id, layout_name) return '{"reload":1}' layout_id = updateLayoutInfo(project_id=project_id, layout_id=layout_id, layout_name=layout_name, layout_info=image) if "saveSelection" in request.json: project = dbSession.query(Project).filter( Project.project_id == project_id).one() project.layout_selected = layout_id dbSession.commit() return jsonify({ "layoutId": layout_id, "displayStrings": parsed.displayStrings() })
def sendMaterialList(): """Email a material list to a supplier""" proj_id = request.args.get('proj_id') project = dbSession.query(Project).filter( Project.project_id == proj_id).one() pdf = None if "pdf" in request.json: if request.json["pdf"] != "": pdf = request.json["pdf"] company = dbSession.query(Company).filter( Company.company_name == project.company_name).one() message = Messages.materialListMessage(company) layout = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one() parsed = DiagramParser.parse(layout.layout_info) attachmentString = Messages.materialListAttachment(project) attachment = Email.makeAttachment(Messages.materialListPath, attachmentString) supplierEmail = request.json["email"] if pdf: attachment = pdf else: attachmentString = Messages.materialListAttachment(project) attachment = Email.makeAttachment(Messages.materialListPath, attachmentString) if attachment is not None: Email.send(app, mail, project.company_name, supplierEmail, "Material list", message, "Material list", attachment) return "{}"
def quoteAttachment(project, customer=None, parsed=None, misc=None, notes=None, misc_modifier_label=None, payment=None, description=None): """Generate the content of a quote attachment and return it""" if customer is None: customer = dbSession.query(Customer).filter( Customer.customer_id == project.customer_id).one() if parsed is None: layout = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one().layout_info parsed = DiagramParser.parse(layout) if notes is None: notes = "" if payment is None: payment = "" if description is None: description = "" appearance = dbSession.query(Appearance).filter( Appearance.appearance_id == project.appearance_selected).one() appearanceValues = Appearances.getAppearanceValues(appearance) prices = QuoteCalculation.prices(parsed, appearanceValues[0], appearanceValues[1], appearanceValues[2], appearanceValues[3]) subtotal = PriceCalculation.subtotal(prices) if misc: subtotal += misc gstPercent = PriceCalculation.gstPercent() gst = subtotal * gstPercent total = subtotal + gst priceStrings = [] for price in prices: priceStrings.append('''<tr class="bordered"> <td class="bordered bordered-right">{name}</td> <td class="right bordered">$ {price}</td> </tr>'''.format(name=price[0], price=PriceCalculation.priceString(price[1]))) if misc: if misc_modifier_label is None: misc_modifier_label = "" if misc_modifier_label.strip() == "": misc_modifier_label = "Adjustments" priceStrings.append('''<tr class="bordered"> <td class="bordered bordered-right">{label}</td> <td class="right bordered">$ {price}</td> </tr>'''.format(price=PriceCalculation.priceString(misc), label=misc_modifier_label)) diagram = dbSession.query(Layout).filter( Layout.layout_id == project.layout_selected).one().layout_info company = dbSession.query(Company).filter( Company.company_name == current_user.company_name).one() now = datetime.datetime.now() date = "{0} {1}, {2}".format(now.strftime("%b"), now.day, now.year) sideBar = Messages._sideBar(company) pageBreak = """ <p style="page-break-after: always" ></p> <p style="page-break-before: always" ></p> """ return """ {sideBar} <div style="float:left; width:70%;"> <p> <span class="greyText bold">DATE</span><br> {date} </p><br> <p> <span class="greyText bold">TO</span><br> {customerName}<br> {customerAddress}<br> {customerPhone} </p><br> <p class="bold"> <span class="greyText">PROJECT TITLE: </span> {projectName}<br> <span class="greyText">DESCRIPTION: </span> {description}<br> <span class="greyText">PAYMENT: </span> {payment} </p><br> <table> <tr> <th class="bordered-white">DESCRIPTION</th> <th>PRICE</th> </tr> {prices} <tr class="tableBreakTop bordered"> <td class="right bordered bordered-right">Subtotal</td> <td class="right bordered"><b>$ {subtotal}</b></td> </tr> <tr class="tableBreak bordered"> <td class="right bordered bordered-right">GST  {gstPercent}%</td> <td class="right bordered"><b>$ {gst}</b></td> </tr> <tr class="greyCell right"> <td><b>Total</b></td> <td class="right"><b>$ {total}</b></td> </tr> </table> <p class="bold">{notes}</p> <b><span class="bottom"> Signature:_____________________________________________ </span></b> </div> <p class="pageNumber">Page 1</p> {pageBreak} {sideBar} <div style="float:left; width:70%;"> <p class="bold">Site Map:</p> <img src="{diagram}"><br> <p class="bold" style="padding-top: 2in;">{disclaimer}</p> <b><span class="bottom"> Signature:_____________________________________________ </span></b> </div> <p class="pageNumber">Page 2</p> """.format(pageBreak=pageBreak, diagram=diagram, prices="".join(priceStrings), subtotal=PriceCalculation.priceString(subtotal), gstPercent=round(gstPercent * Decimal("100"), 2), gst=PriceCalculation.priceString(gst), total=PriceCalculation.priceString(total), date=date, customerName=customer.first_name, customerAddress=project.address, customerPhone=customer.cellphone, projectName=project.project_name, notes=notes, payment=payment, description=description, sideBar=sideBar, disclaimer=company.disclaimer)