adding offers examples

Change-Id: I9f8bd2bad35ba9aa5e3ad86fe1a03fd2d27b4e9d
diff --git a/offers/dining/go/offerFeedGenerator.go b/offers/dining/go/offerFeedGenerator.go
new file mode 100644
index 0000000..14adfbd
--- /dev/null
+++ b/offers/dining/go/offerFeedGenerator.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+	pb "feed/app/generated/ext/maps/booking/offers/proto"
+	"fmt"
+	"log"
+
+	money "google.golang.org/genproto/googleapis/type/money"
+	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+	dayofweek "google.golang.org/genproto/googleapis/type/dayofweek"
+	timeofday "google.golang.org/genproto/googleapis/type/timeofday"
+	proto "google.golang.org/protobuf/proto"
+
+	"google.golang.org/protobuf/encoding/protojson"
+)
+
+func main() {
+	// 200 MB feed file size limit
+	const MaxBytesDataFile = 200 * 1024 * 1024 
+
+	// Create OfferFeed with offers
+	feed := &pb.OfferFeed{}
+
+	// Build the offers
+	offer := &pb.Offer{
+		OfferId:   "offer-1",
+		EntityIds: []string{"dining-1"},
+		OfferSource: pb.OfferSource_OFFER_SOURCE_AGGREGATOR,
+		ActionType:  pb.ActionType_ACTION_TYPE_DINING,
+		OfferModes: []pb.OfferMode{
+			pb.OfferMode_OFFER_MODE_WALK_IN,
+			pb.OfferMode_OFFER_MODE_FREE_RESERVATION,
+		},
+		OfferCategory: pb.OfferCategory_OFFER_CATEGORY_BASE_OFFER,
+		OfferDetails: &pb.OfferDetails{
+			OfferDisplayText: "₹100 off on your order",
+			OfferSpecification: &pb.OfferDetails_DiscountValue{
+        		DiscountValue: &money.Money{
+            		CurrencyCode: "INR",
+            		Units:        100,
+				},
+			},
+		},
+		OfferRestrictions: &pb.OfferRestrictions{
+			CombinableWithOtherOffers: true,
+			CombinableOfferCategories: []pb.OfferCategory{
+				pb.OfferCategory_OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER,
+				pb.OfferCategory_OFFER_CATEGORY_ADD_ON_COUPON_OFFER,
+			},
+		},
+		Terms: &pb.Terms{
+			RestrictedToCertainUsers: false,
+			TermsAndConditions:       "Valid on all menu items.",
+		},
+		ValidityPeriods: []*pb.ValidityPeriod{
+			{
+				ValidPeriod: &pb.ValidityRange{
+					ValidFromTime:    &timestamppb.Timestamp{Seconds: 1687062000},
+					ValidThroughTime: &timestamppb.Timestamp{Seconds: 1956556800},
+				},
+				TimeOfDay: []*pb.TimeOfDayWindow{
+					// Monday - Thursday Window
+					{
+						TimeWindows: &pb.TimeOfDayRange{
+							OpenTime:  &timeofday.TimeOfDay{Hours: 13},
+							CloseTime: &timeofday.TimeOfDay{Hours: 23},
+						},
+						DayOfWeek: []dayofweek.DayOfWeek{
+							dayofweek.DayOfWeek_MONDAY,
+							dayofweek.DayOfWeek_TUESDAY,
+							dayofweek.DayOfWeek_WEDNESDAY,
+							dayofweek.DayOfWeek_THURSDAY,
+						},
+					},
+					// Friday - Sunday Window
+					{
+						TimeWindows: &pb.TimeOfDayRange{
+							OpenTime: &timeofday.TimeOfDay{Hours: 13},
+							CloseTime: &timeofday.TimeOfDay{
+								Hours:   23,
+								Minutes: 59,
+								Seconds: 59,
+							},
+						},
+						DayOfWeek: []dayofweek.DayOfWeek{
+							dayofweek.DayOfWeek_FRIDAY,
+							dayofweek.DayOfWeek_SATURDAY,
+							dayofweek.DayOfWeek_SUNDAY,
+						},
+					},
+				},
+			},
+		},
+		OfferUrl: "https://www.example-restaurant.com/offer/base_offer_1",
+		ImageUrl: "https://www.example-restaurant.com/images/offer_base.jpg",
+	}
+
+	// Example testing for feed size
+	// Protocol buffer message must be less than 2 GiB
+	// https://protobuf.dev/programming-guides/proto-limits/
+	// It is recommended to not exceed 200 MB, as there is an Actions
+	// Center limit of 200 MB per file after compression.
+	offerSize := proto.Size(offer)
+	currentFeedSize := proto.Size(feed)
+
+	if currentFeedSize + offerSize < MaxBytesDataFile {
+		feed.Data = append(feed.Data, offer)
+	} else {
+		// 1. Serialize and save the current 'feed' to a file
+		// 2. Reset 'feed' to a new empty OfferFeed
+		// 3. Add the 'offer' to the new feed
+	}
+
+	// Serialize to JSON
+	marshaler := protojson.MarshalOptions{
+		UseProtoNames: true,
+	}
+
+	jsonOutput, err := marshaler.Marshal(feed)
+	if err != nil {
+		log.Fatalf("Failed to marshal feed: %v", err)
+	}
+
+	fmt.Println(string(jsonOutput))
+}
\ No newline at end of file
diff --git a/offers/dining/java/pom.xml b/offers/dining/java/pom.xml
new file mode 100644
index 0000000..53708e1
--- /dev/null
+++ b/offers/dining/java/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.example.offers</groupId>
+    <artifactId>feed</artifactId>
+    <version>1.0.0</version>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>21.0</java.version>
+        <maven.compiler.source>21</maven.compiler.source>
+        <maven.compiler.target>21</maven.compiler.target>
+        <protobuf.version>4.29.3</protobuf.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>${protobuf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+            <version>${protobuf.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.2.2</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                          <addClasspath>true</addClasspath>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <archive>
+                      <manifest>
+                        <mainClass>com.example.offers.OfferFeedGenerator</mainClass>
+                      </manifest>
+                    </archive>
+                  </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
+                        <phase>package</phase> <!-- bind to the packaging phase -->
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+              <groupId>io.github.ascopes</groupId>
+              <artifactId>protobuf-maven-plugin</artifactId>
+              <configuration>
+                <protoc>${protobuf.version}</protoc>
+              </configuration>
+              <executions>
+                <execution>
+                  <goals>
+                    <goal>generate</goal>
+                  </goals>
+                </execution>
+              </executions>
+            </plugin>
+          </plugins>
+    </build>
+</project>
diff --git a/offers/dining/java/src/main/java/com/example/offers/OfferFeedGenerator.java b/offers/dining/java/src/main/java/com/example/offers/OfferFeedGenerator.java
new file mode 100644
index 0000000..75db6fd
--- /dev/null
+++ b/offers/dining/java/src/main/java/com/example/offers/OfferFeedGenerator.java
@@ -0,0 +1,105 @@
+package com.example.offers;
+
+import com.google.protobuf.util.JsonFormat;
+import ext.maps.booking.feeds.offers.Offer;
+import ext.maps.booking.feeds.offers.OfferFeed;
+import ext.maps.booking.feeds.offers.OfferDetails;
+import ext.maps.booking.feeds.offers.OfferRestrictions;
+import ext.maps.booking.feeds.offers.Terms;
+import ext.maps.booking.feeds.offers.ValidityPeriod;
+import ext.maps.booking.feeds.offers.ValidityRange;
+import ext.maps.booking.feeds.offers.OfferCategory;
+import ext.maps.booking.feeds.offers.OfferMode;
+import ext.maps.booking.feeds.offers.OfferSource;
+import ext.maps.booking.feeds.offers.ActionType;
+import ext.maps.booking.feeds.offers.TimeOfDayWindow;
+import ext.maps.booking.feeds.offers.TimeOfDayRange;
+
+import com.google.type.Money;
+import com.google.protobuf.Timestamp;
+import com.google.type.DayOfWeek;
+import com.google.type.TimeOfDay;
+
+
+public class OfferFeedGenerator {
+
+    // 200 MB
+    public static final int MAX_BYTES_DATA_FILE = 200 * 1024 * 1024;
+  
+    public static void main(String[] args) throws Exception {
+        
+        // Create OfferFeed
+        OfferFeed.Builder feed = OfferFeed.newBuilder();
+
+        // Build the offers
+        Offer offer = Offer.newBuilder()
+            .setOfferId("offer-1")
+            .addEntityIds("dining-1")
+            .setOfferSource(OfferSource.OFFER_SOURCE_AGGREGATOR)
+            .setActionType(ActionType.ACTION_TYPE_DINING)
+            .addOfferModes(OfferMode.OFFER_MODE_WALK_IN)
+            .addOfferModes(OfferMode.OFFER_MODE_FREE_RESERVATION)
+            .setOfferCategory(OfferCategory.OFFER_CATEGORY_BASE_OFFER)
+            .setOfferDetails(OfferDetails.newBuilder()
+                .setOfferDisplayText("₹100 off on your order")
+                .setDiscountValue(Money.newBuilder()
+                    .setCurrencyCode("INR")
+                    .setUnits(100)))
+            .setOfferRestrictions(OfferRestrictions.newBuilder()
+                .setCombinableWithOtherOffers(true)
+                .addCombinableOfferCategories(OfferCategory.OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER)
+                .addCombinableOfferCategories(OfferCategory.OFFER_CATEGORY_ADD_ON_COUPON_OFFER))
+            .setTerms(Terms.newBuilder()
+                .setRestrictedToCertainUsers(false)
+                .setTermsAndConditions("Valid on all menu items."))
+            .addValidityPeriods(ValidityPeriod.newBuilder()
+                .setValidPeriod(ext.maps.booking.feeds.offers.ValidityRange.newBuilder()
+                    .setValidFromTime(Timestamp.newBuilder().setSeconds(1687062000))
+                    .setValidThroughTime(Timestamp.newBuilder().setSeconds(1956556800)))
+                // // Monday - Thursday Window
+                .addTimeOfDay(ext.maps.booking.feeds.offers.TimeOfDayWindow.newBuilder()
+                    .setTimeWindows(ext.maps.booking.feeds.offers.TimeOfDayRange.newBuilder()
+                        .setOpenTime(com.google.type.TimeOfDay.newBuilder().setHours(13))
+                        .setCloseTime(com.google.type.TimeOfDay.newBuilder().setHours(23)))
+                    .addDayOfWeek(DayOfWeek.MONDAY)
+                    .addDayOfWeek(DayOfWeek.TUESDAY)
+                    .addDayOfWeek(DayOfWeek.WEDNESDAY)
+                    .addDayOfWeek(DayOfWeek.THURSDAY))
+                // Friday - Sunday Window
+                .addTimeOfDay(ext.maps.booking.feeds.offers.TimeOfDayWindow.newBuilder()
+                    .setTimeWindows(ext.maps.booking.feeds.offers.TimeOfDayRange.newBuilder()
+                        .setOpenTime(com.google.type.TimeOfDay.newBuilder().setHours(13))
+                        .setCloseTime(com.google.type.TimeOfDay.newBuilder().setHours(23).setMinutes(59).setSeconds(59)))
+                    .addDayOfWeek(DayOfWeek.FRIDAY)
+                    .addDayOfWeek(DayOfWeek.SATURDAY)
+                    .addDayOfWeek(DayOfWeek.SUNDAY))
+            )
+            .setOfferUrl("https://www.example-restaurant.com/offer/base_offer_1")
+            .setImageUrl("https://www.example-restaurant.com/images/offer_base.jpg")
+            .build();
+
+
+        // Example testing for offer feed size
+        // Protocol buffer message must be less than 2 GiB
+        // https://protobuf.dev/programming-guides/proto-limits/
+        // It is recommended to not exceed 200 MB, as there is an Actions
+        // Center limit of 200 MB per file after compression.
+        int offerSize = offer.getSerializedSize();
+        int currentFeedSize = feed.build().getSerializedSize();
+
+        if (currentFeedSize + offerSize < MAX_BYTES_DATA_FILE) {
+            feed.addData(offer);
+        } else {
+            // 1. Serialize and save the current 'feed' to a file
+            // 2. Reset 'feed' to a new empty OfferFeed
+            // 3. Add the 'offer' to the new feed
+        }
+
+        // Serialize to JSON
+        String jsonOutput = JsonFormat.printer()
+            .preservingProtoFieldNames()
+            .print(feed);
+
+        System.out.println(jsonOutput);
+    }
+}
diff --git a/offers/dining/python/offer_feed.py b/offers/dining/python/offer_feed.py
new file mode 100644
index 0000000..8f50f53
--- /dev/null
+++ b/offers/dining/python/offer_feed.py
@@ -0,0 +1,106 @@
+import json
+from google.protobuf.json_format import MessageToDict
+from google.protobuf.timestamp_pb2 import Timestamp
+
+
+# Replace these imports with your actual generated proto package paths
+from generated import offer_pb2
+from generated import money_pb2
+from generated import dayofweek_pb2
+from generated import timeofday_pb2
+
+_MAX_BYTES_DATA_FILE = 200 * 1024 * 1024
+
+def generate_offer_feed():
+
+    # Create OfferFeed
+    feed = offer_pb2.OfferFeed()
+
+    # Build the offers
+    offer = offer_pb2.Offer(
+        offer_id="offer-1",
+        entity_ids=["dining-1"],
+        offer_source=offer_pb2.OFFER_SOURCE_AGGREGATOR,
+        action_type=offer_pb2.ACTION_TYPE_DINING,
+        offer_modes=[
+            offer_pb2.OFFER_MODE_WALK_IN,
+            offer_pb2.OFFER_MODE_FREE_RESERVATION
+        ],
+        offer_category=offer_pb2.OFFER_CATEGORY_BASE_OFFER,
+        offer_details=offer_pb2.OfferDetails(
+            offer_display_text="₹100 off on your order",
+            # Note: If this is a 'oneof', you set the field name directly
+            discount_value=money_pb2.Money(
+                currency_code="INR",
+                units=100
+            )
+        ),
+        offer_restrictions=offer_pb2.OfferRestrictions(
+            combinable_with_other_offers=True,
+            combinable_offer_categories=[
+                offer_pb2.OFFER_CATEGORY_ADD_ON_PAYMENT_OFFER,
+                offer_pb2.OFFER_CATEGORY_ADD_ON_COUPON_OFFER
+            ]
+        ),
+        terms=offer_pb2.Terms(
+            restricted_to_certain_users=False,
+            terms_and_conditions="Valid on all menu items."
+        ),
+        validity_periods=[
+            offer_pb2.ValidityPeriod(
+                valid_period=offer_pb2.ValidityRange(
+                    valid_from_time=Timestamp(seconds=1687062000),
+                    valid_through_time=Timestamp(seconds=1956556800)
+                ),
+                time_of_day=[
+                    # Monday - Thursday Window
+                    offer_pb2.TimeOfDayWindow(
+                        time_windows=offer_pb2.TimeOfDayRange(
+                            open_time=timeofday_pb2.TimeOfDay(hours=13),
+                            close_time=timeofday_pb2.TimeOfDay(hours=23)
+                        ),
+                        day_of_week=[
+                            dayofweek_pb2.DayOfWeek.MONDAY,
+                            dayofweek_pb2.DayOfWeek.TUESDAY,
+                            dayofweek_pb2.DayOfWeek.WEDNESDAY,
+                            dayofweek_pb2.DayOfWeek.THURSDAY
+                        ]
+                    ),
+                    # Friday - Sunday Window
+                    offer_pb2.TimeOfDayWindow(
+                        time_windows=offer_pb2.TimeOfDayRange(
+                            open_time=timeofday_pb2.TimeOfDay(hours=13),
+                            close_time=timeofday_pb2.TimeOfDay(hours=23, minutes=59, seconds=59)
+                        ),
+                        day_of_week=[
+                            dayofweek_pb2.DayOfWeek.FRIDAY,
+                            dayofweek_pb2.DayOfWeek.SATURDAY,
+                            dayofweek_pb2.DayOfWeek.SUNDAY
+                        ]
+                    )
+                ]
+            )
+        ],
+        offer_url="https://www.example-restaurant.com/offer/base_offer_1",
+        image_url="https://www.example-restaurant.com/images/offer_base.jpg"
+    )
+
+    # Example testing for menu feed size
+    # Protocol buffer message must be less than 2 GiB
+    # https://protobuf.dev/programming-guides/proto-limits/
+    # It is recommended to not exceed 200 MB, as there is an Actions
+    # Center limit of 200 MB per file after compression.
+    if feed.ByteSize() + offer.ByteSize()  < _MAX_BYTES_DATA_FILE:
+	    feed.data.append(offer)
+    # else write current feed to file and start a new feed
+
+    # Serialize to JSON
+    # preserving_proto_field_names=True ensures camelCase becomes snake_case if defined that way in .proto
+    json_output = json.dumps(
+        MessageToDict(feed, preserving_proto_field_name=True)
+    )
+
+    print(json_output)
+
+if __name__ == "__main__":
+    generate_offer_feed()
\ No newline at end of file