예제 #1
0
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
예제 #2
0
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
    }
예제 #3
0
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 "{}"
예제 #4
0
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)
예제 #5
0
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})
예제 #6
0
	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)
예제 #7
0
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})
예제 #8
0
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()
    })
예제 #9
0
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 "{}"
예제 #10
0
    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 &emsp;{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)